Refactored job line edit modal to use redux so that it can be an independent form. Created general modals reducer to manage all modals.
This commit is contained in:
@@ -15,107 +15,168 @@ export default ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
//TODO Add
|
//TODO Add
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row type='flex' justify='space-around' align='middle'>
|
<Row type="flex" justify="space-around" align="middle">
|
||||||
{logo ? (
|
{logo ? (
|
||||||
<Col span={4}>
|
<Col span={3}>
|
||||||
<img alt='Shop Logo' src={logo} style={{ height: "40px" }} />
|
<img alt="Shop Logo" src={logo} style={{ height: "40px" }} />
|
||||||
</Col>
|
</Col>
|
||||||
) : null}
|
) : null}
|
||||||
<Col span={14}>
|
<Col span={14}>
|
||||||
<Menu
|
{landingHeader ? (
|
||||||
theme='dark'
|
<Menu
|
||||||
className='header'
|
theme="dark"
|
||||||
selectedKeys={selectedNavItem}
|
className="header"
|
||||||
mode='horizontal'
|
selectedKeys={selectedNavItem}
|
||||||
onClick={handleMenuClick}>
|
mode="horizontal"
|
||||||
<Menu.Item key='home'>
|
onClick={handleMenuClick}
|
||||||
<Link to='/manage'>
|
>
|
||||||
<Icon type='home' />
|
<ManageSignInButton />
|
||||||
{t("menus.header.home")}
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.SubMenu title={t("menus.header.jobs")}>
|
|
||||||
<Menu.Item key='schedule'>
|
|
||||||
<Link to='/manage/schedule'>
|
|
||||||
<Icon type='calendar' />
|
|
||||||
{t("menus.header.schedule")}
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key='activejobs'>
|
|
||||||
<Link to='/manage/jobs'>{t("menus.header.activejobs")}</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key='availablejobs'>
|
|
||||||
<Link to='/manage/available'>
|
|
||||||
{t("menus.header.availablejobs")}
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu.SubMenu>
|
|
||||||
|
|
||||||
<Menu.SubMenu title={t("menus.header.customers")}>
|
|
||||||
<Menu.Item key='owners'>
|
|
||||||
<Link to='/manage/owners'>
|
|
||||||
<Icon type='team' />
|
|
||||||
{t("menus.header.owners")}
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key='vehicles'>
|
|
||||||
<Link to='/manage/vehicles'>
|
|
||||||
<Icon type='car' />
|
|
||||||
{t("menus.header.vehicles")}
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu.SubMenu>
|
|
||||||
<Menu.SubMenu title={t("menus.header.shop")}>
|
|
||||||
<Menu.Item key='shop'>
|
|
||||||
<Link to='/manage/shop'>{t("menus.header.shop_config")}</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key='shop-vendors'>
|
|
||||||
<Link to='/manage/shop/vendors'>
|
|
||||||
{t("menus.header.shop_vendors")}
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu.SubMenu>
|
|
||||||
|
|
||||||
<Menu.SubMenu
|
|
||||||
title={
|
|
||||||
<div>
|
|
||||||
<Avatar
|
|
||||||
size='medium'
|
|
||||||
alt='Avatar'
|
|
||||||
src={currentUser.photoURL ? currentUser.photoURL : UserImage}
|
|
||||||
style={{ margin: "10px" }}
|
|
||||||
/>
|
|
||||||
{currentUser.displayName || t("general.labels.unknown")}
|
|
||||||
</div>
|
|
||||||
}>
|
|
||||||
<Menu.Item onClick={signOutStart()}>
|
|
||||||
{t("user.actions.signout")}
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item>
|
|
||||||
<Link to='/manage/profile'>{t("menus.currentuser.profile")}</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.SubMenu
|
<Menu.SubMenu
|
||||||
title={
|
title={
|
||||||
<span>
|
<div>
|
||||||
<Icon type='global' />
|
<Avatar
|
||||||
<span>{t("menus.currentuser.languageselector")}</span>
|
size="medium"
|
||||||
</span>
|
alt="Avatar"
|
||||||
}>
|
src={
|
||||||
<Menu.Item actiontype='lang-select' key='en_us'>
|
currentUser.photoURL ? currentUser.photoURL : UserImage
|
||||||
{t("general.languages.english")}
|
}
|
||||||
|
style={{ margin: "10px" }}
|
||||||
|
/>
|
||||||
|
{currentUser.displayName || t("general.labels.unknown")}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Menu.Item onClick={signOutStart()}>
|
||||||
|
{t("user.actions.signout")}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Item actiontype='lang-select' key='fr'>
|
<Menu.Item>
|
||||||
{t("general.languages.french")}
|
<Link to="/manage/profile">
|
||||||
|
{t("menus.currentuser.profile")}
|
||||||
|
</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Item actiontype='lang-select' key='es'>
|
<Menu.SubMenu
|
||||||
{t("general.languages.spanish")}
|
title={
|
||||||
|
<span>
|
||||||
|
<Icon type="global" />
|
||||||
|
<span>{t("menus.currentuser.languageselector")}</span>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Menu.Item actiontype="lang-select" key="en_us">
|
||||||
|
{t("general.languages.english")}
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item actiontype="lang-select" key="fr">
|
||||||
|
{t("general.languages.french")}
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item actiontype="lang-select" key="es">
|
||||||
|
{t("general.languages.spanish")}
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu.SubMenu>
|
||||||
|
</Menu.SubMenu>
|
||||||
|
</Menu>
|
||||||
|
) : (
|
||||||
|
<Menu
|
||||||
|
theme="dark"
|
||||||
|
className="header"
|
||||||
|
selectedKeys={selectedNavItem}
|
||||||
|
mode="horizontal"
|
||||||
|
onClick={handleMenuClick}
|
||||||
|
>
|
||||||
|
<Menu.Item key="home">
|
||||||
|
<Link to="/manage">
|
||||||
|
<Icon type="home" />
|
||||||
|
{t("menus.header.home")}
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.SubMenu title={t("menus.header.jobs")}>
|
||||||
|
<Menu.Item key="schedule">
|
||||||
|
<Link to="/manage/schedule">
|
||||||
|
<Icon type="calendar" />
|
||||||
|
{t("menus.header.schedule")}
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item key="activejobs">
|
||||||
|
<Link to="/manage/jobs">{t("menus.header.activejobs")}</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item key="availablejobs">
|
||||||
|
<Link to="/manage/available">
|
||||||
|
{t("menus.header.availablejobs")}
|
||||||
|
</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</Menu.SubMenu>
|
</Menu.SubMenu>
|
||||||
</Menu.SubMenu>
|
<Menu.SubMenu title={t("menus.header.customers")}>
|
||||||
</Menu>
|
<Menu.Item key="owners">
|
||||||
|
<Link to="/manage/owners">
|
||||||
|
<Icon type="team" />
|
||||||
|
{t("menus.header.owners")}
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item key="vehicles">
|
||||||
|
<Link to="/manage/vehicles">
|
||||||
|
<Icon type="car" />
|
||||||
|
{t("menus.header.vehicles")}
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu.SubMenu>
|
||||||
|
<Menu.SubMenu title={t("menus.header.shop")}>
|
||||||
|
<Menu.Item key="shop">
|
||||||
|
<Link to="/manage/shop">{t("menus.header.shop_config")}</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item key="shop-vendors">
|
||||||
|
<Link to="/manage/shop/vendors">
|
||||||
|
{t("menus.header.shop_vendors")}
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu.SubMenu>
|
||||||
|
|
||||||
|
<Menu.SubMenu
|
||||||
|
title={
|
||||||
|
<div>
|
||||||
|
<Avatar
|
||||||
|
size="medium"
|
||||||
|
alt="Avatar"
|
||||||
|
src={
|
||||||
|
currentUser.photoURL ? currentUser.photoURL : UserImage
|
||||||
|
}
|
||||||
|
style={{ margin: "10px" }}
|
||||||
|
/>
|
||||||
|
{currentUser.displayName || t("general.labels.unknown")}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Menu.Item onClick={signOutStart()}>
|
||||||
|
{t("user.actions.signout")}
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item>
|
||||||
|
<Link to="/manage/profile">
|
||||||
|
{t("menus.currentuser.profile")}
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.SubMenu
|
||||||
|
title={
|
||||||
|
<span>
|
||||||
|
<Icon type="global" />
|
||||||
|
<span>{t("menus.currentuser.languageselector")}</span>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Menu.Item actiontype="lang-select" key="en_us">
|
||||||
|
{t("general.languages.english")}
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item actiontype="lang-select" key="fr">
|
||||||
|
{t("general.languages.french")}
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item actiontype="lang-select" key="es">
|
||||||
|
{t("general.languages.spanish")}
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu.SubMenu>
|
||||||
|
</Menu.SubMenu>
|
||||||
|
</Menu>
|
||||||
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={4}>{!landingHeader ? null : <ManageSignInButton />}</Col>
|
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import { Button, Input, Table } from "antd";
|
import { Button, Input, Table } from "antd";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import { alphaSort } from "../../utils/sorters";
|
import { alphaSort } from "../../utils/sorters";
|
||||||
import { Link } from "react-router-dom";
|
|
||||||
//import EditableCell from "./job-lines-cell.component";
|
|
||||||
import AllocationsAssignmentContainer from "../allocations-assignment/allocations-assignment.container";
|
import AllocationsAssignmentContainer from "../allocations-assignment/allocations-assignment.container";
|
||||||
import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container";
|
|
||||||
import AllocationsBulkAssignmentContainer from "../allocations-bulk-assignment/allocations-bulk-assignment.container";
|
import AllocationsBulkAssignmentContainer from "../allocations-bulk-assignment/allocations-bulk-assignment.container";
|
||||||
import JobLineUpsertModalContainer from "../job-lines-upsert-modal/job-lines-upsert-modal.container";
|
import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container";
|
||||||
|
|
||||||
export default function JobLinesComponent({
|
export default function JobLinesComponent({
|
||||||
loading,
|
loading,
|
||||||
refetch,
|
refetch,
|
||||||
@@ -18,8 +17,7 @@ export default function JobLinesComponent({
|
|||||||
setSelectedLines,
|
setSelectedLines,
|
||||||
partsOrderModalVisible,
|
partsOrderModalVisible,
|
||||||
jobId,
|
jobId,
|
||||||
editLineModalVisible,
|
setJobLineEditContext
|
||||||
lineToEdit
|
|
||||||
}) {
|
}) {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
sortedInfo: {}
|
sortedInfo: {}
|
||||||
@@ -145,9 +143,8 @@ export default function JobLinesComponent({
|
|||||||
{record.allocations && record.allocations.length > 0
|
{record.allocations && record.allocations.length > 0
|
||||||
? record.allocations.map(item => (
|
? record.allocations.map(item => (
|
||||||
<div
|
<div
|
||||||
key={
|
key={item.id}
|
||||||
item.id
|
>{`${item.employee.first_name} ${item.employee.last_name} (${item.hours})`}</div>
|
||||||
}>{`${item.employee.first_name} ${item.employee.last_name} (${item.hours})`}</div>
|
|
||||||
))
|
))
|
||||||
: null}
|
: null}
|
||||||
<AllocationsAssignmentContainer
|
<AllocationsAssignmentContainer
|
||||||
@@ -167,9 +164,14 @@ export default function JobLinesComponent({
|
|||||||
<span>
|
<span>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
lineToEdit[1](record);
|
setJobLineEditContext({
|
||||||
editLineModalVisible[1](true);
|
actions: { refetch: refetch },
|
||||||
}}>
|
context: record
|
||||||
|
});
|
||||||
|
//lineToEdit[1](record);
|
||||||
|
//editLineModalVisible[1](true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
{t("general.actions.edit")}
|
{t("general.actions.edit")}
|
||||||
</Button>
|
</Button>
|
||||||
</span>
|
</span>
|
||||||
@@ -201,14 +203,6 @@ export default function JobLinesComponent({
|
|||||||
jobId={jobId}
|
jobId={jobId}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<JobLineUpsertModalContainer
|
|
||||||
jobId={jobId}
|
|
||||||
visible={editLineModalVisible[0]}
|
|
||||||
changeVisibility={editLineModalVisible[1]}
|
|
||||||
refetch={refetch}
|
|
||||||
existingLine={lineToEdit[0]}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Table
|
<Table
|
||||||
title={() => {
|
title={() => {
|
||||||
return (
|
return (
|
||||||
@@ -222,7 +216,8 @@ export default function JobLinesComponent({
|
|||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
disabled={selectedLines.length > 0 ? false : true}
|
disabled={selectedLines.length > 0 ? false : true}
|
||||||
onClick={() => setPartsModalVisible(true)}>
|
onClick={() => setPartsModalVisible(true)}
|
||||||
|
>
|
||||||
{t("parts.actions.order")}
|
{t("parts.actions.order")}
|
||||||
</Button>
|
</Button>
|
||||||
<AllocationsBulkAssignmentContainer
|
<AllocationsBulkAssignmentContainer
|
||||||
@@ -234,7 +229,7 @@ export default function JobLinesComponent({
|
|||||||
}}
|
}}
|
||||||
{...formItemLayout}
|
{...formItemLayout}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
size='small'
|
size="small"
|
||||||
expandedRowRender={record => (
|
expandedRowRender={record => (
|
||||||
<div style={{ margin: 0 }}>
|
<div style={{ margin: 0 }}>
|
||||||
<strong>{t("parts_orders.labels.orderhistory")}</strong>
|
<strong>{t("parts_orders.labels.orderhistory")}</strong>
|
||||||
@@ -252,11 +247,14 @@ export default function JobLinesComponent({
|
|||||||
pagination={{ position: "top", defaultPageSize: 25 }}
|
pagination={{ position: "top", defaultPageSize: 25 }}
|
||||||
rowSelection={{
|
rowSelection={{
|
||||||
// selectedRowKeys: selectedLines,
|
// selectedRowKeys: selectedLines,
|
||||||
|
onSelectAll: (selected, selectedRows, changeRows) => {
|
||||||
|
setSelectedLines(selectedRows);
|
||||||
|
},
|
||||||
onSelect: (record, selected, selectedRows, nativeEvent) =>
|
onSelect: (record, selected, selectedRows, nativeEvent) =>
|
||||||
setSelectedLines(selectedRows)
|
setSelectedLines(selectedRows)
|
||||||
}}
|
}}
|
||||||
columns={columns.map(item => ({ ...item }))}
|
columns={columns.map(item => ({ ...item }))}
|
||||||
rowKey='id'
|
rowKey="id"
|
||||||
dataSource={jobLines}
|
dataSource={jobLines}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -5,9 +5,16 @@ import { GET_JOB_LINES_BY_PK } from "../../graphql/jobs-lines.queries";
|
|||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import JobLinesComponent from "./job-lines.component";
|
import JobLinesComponent from "./job-lines.component";
|
||||||
|
|
||||||
//export default Form.create({ name: "JobsDetailJobLines" })(
|
import { connect } from "react-redux";
|
||||||
|
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||||
export default function JobLinesContainer({ jobId }) {
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
setJobLineEditContext: context =>
|
||||||
|
dispatch(setModalContext({ context: context, modal: "jobLineEdit" }))
|
||||||
|
});
|
||||||
|
export default connect(
|
||||||
|
null,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(function JobLinesContainer({ jobId, setJobLineEditContext }) {
|
||||||
const { loading, error, data, refetch } = useQuery(GET_JOB_LINES_BY_PK, {
|
const { loading, error, data, refetch } = useQuery(GET_JOB_LINES_BY_PK, {
|
||||||
variables: { id: jobId },
|
variables: { id: jobId },
|
||||||
fetchPolicy: "network-only"
|
fetchPolicy: "network-only"
|
||||||
@@ -16,10 +23,8 @@ export default function JobLinesContainer({ jobId }) {
|
|||||||
const [searchText, setSearchText] = useState("");
|
const [searchText, setSearchText] = useState("");
|
||||||
const [selectedLines, setSelectedLines] = useState([]);
|
const [selectedLines, setSelectedLines] = useState([]);
|
||||||
const partsOrderModalVisible = useState(false);
|
const partsOrderModalVisible = useState(false);
|
||||||
const editLineModalVisible = useState(false);
|
|
||||||
const lineToEdit = useState({});
|
|
||||||
|
|
||||||
if (error) return <AlertComponent message={error.message} type='error' />;
|
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<JobLinesComponent
|
<JobLinesComponent
|
||||||
@@ -61,9 +66,7 @@ export default function JobLinesContainer({ jobId }) {
|
|||||||
setSelectedLines={setSelectedLines}
|
setSelectedLines={setSelectedLines}
|
||||||
partsOrderModalVisible={partsOrderModalVisible}
|
partsOrderModalVisible={partsOrderModalVisible}
|
||||||
jobId={jobId}
|
jobId={jobId}
|
||||||
editLineModalVisible={editLineModalVisible}
|
setJobLineEditContext={setJobLineEditContext}
|
||||||
lineToEdit={lineToEdit}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
//);
|
|
||||||
|
|||||||
@@ -1,31 +1,33 @@
|
|||||||
import { Input, Modal } from "antd";
|
import { Modal, Form } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
export default function JobLinesUpsertModalComponent({
|
export default function JobLinesUpsertModalComponent({
|
||||||
visible,
|
visible,
|
||||||
changeVisibility,
|
jobLine,
|
||||||
lineState,
|
handleOk,
|
||||||
setLineState,
|
handleCancel,
|
||||||
updateExistingLine,
|
handleSubmit,
|
||||||
insertNewLine
|
form
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const handleChange = e => {
|
//const { getFieldDecorator, isFieldsTouched, resetFields } = form;
|
||||||
setLineState({ ...lineState, [e.target.name]: e.target.value });
|
console.log("jobLine", jobLine);
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title={lineState.id ? t("joblines.label.edit") : t("joblines.label.new")}
|
title={
|
||||||
|
jobLine && jobLine.id
|
||||||
|
? t("joblines.labels.edit")
|
||||||
|
: t("joblines.labels.new")
|
||||||
|
}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
okText={t("general.labels.save")}
|
okText={t("general.labels.save")}
|
||||||
onOk={() => {
|
onOk={handleOk}
|
||||||
lineState.id ? updateExistingLine() : insertNewLine();
|
onCancel={handleCancel}
|
||||||
}}
|
>
|
||||||
onCancel={() => {
|
<Form onSubmit={handleSubmit} autoComplete={"off"}>
|
||||||
changeVisibility(false);
|
{JSON.stringify(jobLine)}
|
||||||
}}>
|
</Form>
|
||||||
<Input.TextArea rows={8} value={lineState.text} onChange={handleChange} />
|
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,71 +1,102 @@
|
|||||||
import { notification } from "antd";
|
import { Form, notification } from "antd";
|
||||||
import React, { useEffect, useState } from "react";
|
import React from "react";
|
||||||
import { useMutation } from "react-apollo";
|
import { useMutation } from "react-apollo";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
import {
|
import {
|
||||||
INSERT_NEW_JOB_LINE,
|
INSERT_NEW_JOB_LINE,
|
||||||
UPDATE_JOB_LINE
|
UPDATE_JOB_LINE
|
||||||
} from "../../graphql/jobs-lines.queries";
|
} from "../../graphql/jobs-lines.queries";
|
||||||
|
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
||||||
|
import { selectJobLineEditModal } from "../../redux/modals/modals.selectors";
|
||||||
import JobLinesUpdsertModal from "./job-lines-upsert-modal.component";
|
import JobLinesUpdsertModal from "./job-lines-upsert-modal.component";
|
||||||
|
|
||||||
export default function JobLinesUpsertModalContainer({
|
const mapStateToProps = createStructuredSelector({
|
||||||
jobId,
|
jobLineEditModal: selectJobLineEditModal
|
||||||
visible,
|
});
|
||||||
changeVisibility,
|
const mapDispatchToProps = dispatch => ({
|
||||||
refetch,
|
toggleModalVisible: () => dispatch(toggleModalVisible("jobLineEdit"))
|
||||||
existingLine
|
});
|
||||||
|
|
||||||
|
function JobLinesUpsertModalContainer({
|
||||||
|
jobLineEditModal,
|
||||||
|
toggleModalVisible,
|
||||||
|
form
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [insertJobLine] = useMutation(INSERT_NEW_JOB_LINE);
|
const [insertJobLine] = useMutation(INSERT_NEW_JOB_LINE);
|
||||||
const [updateJobLine] = useMutation(UPDATE_JOB_LINE);
|
const [updateJobLine] = useMutation(UPDATE_JOB_LINE);
|
||||||
|
|
||||||
const [lineState, setLineState] = useState({});
|
const handleSubmit = e => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
useEffect(() => {
|
form.validateFieldsAndScroll((err, values) => {
|
||||||
//Required to prevent infinite looping.
|
if (err) {
|
||||||
if (existingLine) {
|
notification["error"]({
|
||||||
setLineState(existingLine);
|
message: t("jobs.errors.validationtitle"),
|
||||||
}
|
description: t("jobs.errors.validation")
|
||||||
}, [existingLine]);
|
});
|
||||||
|
}
|
||||||
const insertNewLine = () => {
|
if (!err) {
|
||||||
insertJobLine({
|
if (true) {
|
||||||
variables: {
|
insertJobLine({
|
||||||
lineInput: [{ ...lineState, jobid: jobId }]
|
variables: {
|
||||||
|
//lineInput: [{ ...lineState, jobid: jobId }]
|
||||||
|
}
|
||||||
|
}).then(r => {
|
||||||
|
if (jobLineEditModal.actions.refetch)
|
||||||
|
jobLineEditModal.actions.refetch();
|
||||||
|
toggleModalVisible();
|
||||||
|
notification["success"]({
|
||||||
|
message: t("joblines.successes.create")
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false) {
|
||||||
|
//Required, otherwise unable to spread in new note prop.
|
||||||
|
//delete lineState.__typename;
|
||||||
|
updateJobLine({
|
||||||
|
variables: {
|
||||||
|
//lineId: lineState.id,
|
||||||
|
//line: lineState
|
||||||
|
}
|
||||||
|
}).then(r => {
|
||||||
|
notification["success"]({
|
||||||
|
message: t("joblines.successes.updated")
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (jobLineEditModal.actions.refetch)
|
||||||
|
jobLineEditModal.actions.refetch();
|
||||||
|
toggleModalVisible();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}).then(r => {
|
|
||||||
refetch();
|
|
||||||
changeVisibility(!visible);
|
|
||||||
notification["success"]({
|
|
||||||
message: t("joblines.successes.create")
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateExistingLine = () => {
|
const handleOk = () => {
|
||||||
//Required, otherwise unable to spread in new note prop.
|
//lineState.id ? updateExistingLine() : insertNewLine();
|
||||||
delete lineState.__typename;
|
|
||||||
updateJobLine({
|
|
||||||
variables: {
|
|
||||||
lineId: lineState.id,
|
|
||||||
line: lineState
|
|
||||||
}
|
|
||||||
}).then(r => {
|
|
||||||
notification["success"]({
|
|
||||||
message: t("joblines.successes.updated")
|
|
||||||
});
|
|
||||||
});
|
|
||||||
refetch();
|
|
||||||
changeVisibility(!visible);
|
|
||||||
};
|
};
|
||||||
|
const handleCancel = () => {
|
||||||
|
toggleModalVisible();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<JobLinesUpdsertModal
|
<JobLinesUpdsertModal
|
||||||
visible={visible}
|
visible={jobLineEditModal.visible}
|
||||||
changeVisibility={changeVisibility}
|
jobLine={jobLineEditModal.context}
|
||||||
updateExistingLine={updateExistingLine}
|
handleSubmit={handleSubmit}
|
||||||
insertNewLine={insertNewLine}
|
handleOk={handleOk}
|
||||||
lineState={lineState}
|
handleCancel={handleCancel}
|
||||||
setLineState={setLineState}
|
form={form}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(
|
||||||
|
Form.create({ name: "JobsDetailPageContainer" })(JobLinesUpsertModalContainer)
|
||||||
|
);
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
import { Form, Icon, Tabs } from "antd";
|
import { Form, Icon, Tabs } from "antd";
|
||||||
import React, { useContext } from "react";
|
import React, { useContext } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { FaHardHat, FaInfo, FaRegStickyNote, FaShieldAlt } from "react-icons/fa";
|
import {
|
||||||
|
FaHardHat,
|
||||||
|
FaInfo,
|
||||||
|
FaRegStickyNote,
|
||||||
|
FaShieldAlt
|
||||||
|
} from "react-icons/fa";
|
||||||
import ResetForm from "../../components/form-items-formatted/reset-form-item.component";
|
import ResetForm from "../../components/form-items-formatted/reset-form-item.component";
|
||||||
import JobsLinesContainer from "../../components/job-detail-lines/job-lines.container";
|
import JobsLinesContainer from "../../components/job-detail-lines/job-lines.container";
|
||||||
import JobsDetailClaims from "../../components/jobs-detail-claims/jobs-detail-claims.component";
|
import JobsDetailClaims from "../../components/jobs-detail-claims/jobs-detail-claims.component";
|
||||||
@@ -13,6 +18,7 @@ import JobsDocumentsContainer from "../../components/jobs-documents/jobs-documen
|
|||||||
import JobNotesContainer from "../../components/jobs-notes/jobs-notes.container";
|
import JobNotesContainer from "../../components/jobs-notes/jobs-notes.container";
|
||||||
import ScheduleJobModalContainer from "../../components/schedule-job-modal/schedule-job-modal.container";
|
import ScheduleJobModalContainer from "../../components/schedule-job-modal/schedule-job-modal.container";
|
||||||
import JobDetailFormContext from "./jobs-detail.page.context";
|
import JobDetailFormContext from "./jobs-detail.page.context";
|
||||||
|
import JobLineUpsertModalContainer from "../../components/job-lines-upsert-modal/job-lines-upsert-modal.container";
|
||||||
|
|
||||||
export default function JobsDetailPage({
|
export default function JobsDetailPage({
|
||||||
job,
|
job,
|
||||||
@@ -46,6 +52,8 @@ export default function JobsDetailPage({
|
|||||||
refetch={refetch}
|
refetch={refetch}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<JobLineUpsertModalContainer />
|
||||||
|
|
||||||
<Form onSubmit={handleSubmit} {...formItemLayout} autoComplete={"off"}>
|
<Form onSubmit={handleSubmit} {...formItemLayout} autoComplete={"off"}>
|
||||||
<JobsDetailHeader
|
<JobsDetailHeader
|
||||||
job={job}
|
job={job}
|
||||||
|
|||||||
12
client/src/redux/modals/modals.actions.js
Normal file
12
client/src/redux/modals/modals.actions.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import ModalsActionTypes from "./modals.types";
|
||||||
|
|
||||||
|
export const toggleModalVisible = modalName => ({
|
||||||
|
type: ModalsActionTypes.TOGGLE_MODAL_VISIBLE,
|
||||||
|
payload: modalName
|
||||||
|
});
|
||||||
|
|
||||||
|
//Modal Context: {context (context object), modal(name of modal)}
|
||||||
|
export const setModalContext = modalContext => ({
|
||||||
|
type: ModalsActionTypes.SET_MODAL_CONTEXT,
|
||||||
|
payload: modalContext
|
||||||
|
});
|
||||||
37
client/src/redux/modals/modals.reducer.js
Normal file
37
client/src/redux/modals/modals.reducer.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import ModalsActionTypes from "./modals.types";
|
||||||
|
|
||||||
|
const INITIAL_STATE = {
|
||||||
|
jobLineEdit: {
|
||||||
|
visible: false,
|
||||||
|
context: null,
|
||||||
|
actions: {
|
||||||
|
refetch: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const modalsReducer = (state = INITIAL_STATE, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case ModalsActionTypes.TOGGLE_MODAL_VISIBLE:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
[action.payload]: {
|
||||||
|
...state[action.payload],
|
||||||
|
visible: !state[action.payload].visible
|
||||||
|
}
|
||||||
|
};
|
||||||
|
case ModalsActionTypes.SET_MODAL_CONTEXT:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
[action.payload.modal]: {
|
||||||
|
...state[action.payload.modal],
|
||||||
|
...action.payload.context,
|
||||||
|
visible: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default modalsReducer;
|
||||||
24
client/src/redux/modals/modals.sagas.js
Normal file
24
client/src/redux/modals/modals.sagas.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { all } from "redux-saga/effects";
|
||||||
|
|
||||||
|
// export function* onSendEmail() {
|
||||||
|
// yield takeLatest(EmailActionTypes.SEND_EMAIL, sendEmail);
|
||||||
|
// }
|
||||||
|
// export function* sendEmail(payload) {
|
||||||
|
// try {
|
||||||
|
// console.log("Sending thta email", payload);
|
||||||
|
// axios.post("/sendemail", payload).then(response => {
|
||||||
|
// console.log(JSON.stringify(response));
|
||||||
|
// put(sendEmailSuccess());
|
||||||
|
// });
|
||||||
|
// } catch (error) {
|
||||||
|
// console.log("Error in sendEmail saga.");
|
||||||
|
// yield put(sendEmailFailure(error.message));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
export function* modalsSagas() {
|
||||||
|
yield all([
|
||||||
|
//call(onSendEmail),
|
||||||
|
]);
|
||||||
|
}
|
||||||
9
client/src/redux/modals/modals.selectors.js
Normal file
9
client/src/redux/modals/modals.selectors.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { createSelector } from "reselect";
|
||||||
|
|
||||||
|
const selectModals = state => state.modals;
|
||||||
|
|
||||||
|
export const selectJobLineEditModal = createSelector(
|
||||||
|
[selectModals],
|
||||||
|
modals => modals.jobLineEdit
|
||||||
|
);
|
||||||
|
|
||||||
5
client/src/redux/modals/modals.types.js
Normal file
5
client/src/redux/modals/modals.types.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const ModalActionTypes = {
|
||||||
|
TOGGLE_MODAL_VISIBLE: "TOGGLE_MODAL_VISIBLE",
|
||||||
|
SET_MODAL_CONTEXT: "SET_JOBLINEEDIT_CONTEXT"
|
||||||
|
};
|
||||||
|
export default ModalActionTypes;
|
||||||
@@ -5,18 +5,19 @@ import storage from "redux-persist/lib/storage";
|
|||||||
import userReducer from "./user/user.reducer";
|
import userReducer from "./user/user.reducer";
|
||||||
import messagingReducer from "./messaging/messaging.reducer";
|
import messagingReducer from "./messaging/messaging.reducer";
|
||||||
import emailReducer from "./email/email.reducer";
|
import emailReducer from "./email/email.reducer";
|
||||||
|
import modalsReducer from './modals/modals.reducer'
|
||||||
const persistConfig = {
|
const persistConfig = {
|
||||||
key: "root",
|
key: "root",
|
||||||
storage,
|
storage,
|
||||||
//whitelist: ["user"]
|
//whitelist: ["user"]
|
||||||
blacklist: ["user", "email", "messaging"]
|
blacklist: ["user", "email", "messaging", "modals"]
|
||||||
};
|
};
|
||||||
|
|
||||||
const rootReducer = combineReducers({
|
const rootReducer = combineReducers({
|
||||||
user: userReducer,
|
user: userReducer,
|
||||||
messaging: messagingReducer,
|
messaging: messagingReducer,
|
||||||
email: emailReducer
|
email: emailReducer,
|
||||||
|
modals: modalsReducer
|
||||||
});
|
});
|
||||||
|
|
||||||
export default persistReducer(persistConfig, rootReducer);
|
export default persistReducer(persistConfig, rootReducer);
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { all, call } from "redux-saga/effects";
|
|||||||
import { userSagas } from "./user/user.sagas";
|
import { userSagas } from "./user/user.sagas";
|
||||||
import { messagingSagas } from "./messaging/messaging.sagas";
|
import { messagingSagas } from "./messaging/messaging.sagas";
|
||||||
import { emailSagas } from "./email/email.sagas";
|
import { emailSagas } from "./email/email.sagas";
|
||||||
|
import { modalsSagas } from "./modals/modals.sagas";
|
||||||
export default function* rootSaga() {
|
export default function* rootSaga() {
|
||||||
yield all([call(userSagas), call(messagingSagas), call(emailSagas)]);
|
yield all([call(userSagas), call(messagingSagas), call(emailSagas),
|
||||||
|
call(modalsSagas)]);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user