Added base jobline edit modal. To be confirmed if required.

This commit is contained in:
Patrick Fic
2020-02-21 09:27:05 -08:00
parent a51915c0ea
commit 1476781fa8
14 changed files with 211 additions and 29 deletions

View File

@@ -1,4 +1,4 @@
<babeledit_project version="1.2" be_version="2.6.1"> <babeledit_project be_version="2.6.1" version="1.2">
<!-- <!--
BabelEdit project file BabelEdit project file
@@ -1701,6 +1701,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>line_ind</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>mod_lb_hrs</name> <name>mod_lb_hrs</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>

View File

@@ -13,6 +13,7 @@ export default connect(
mapStateToProps, mapStateToProps,
null null
)(function AllocationsBulkAssignmentComponent({ )(function AllocationsBulkAssignmentComponent({
disabled,
bodyshop, bodyshop,
handleAssignment, handleAssignment,
assignment, assignment,
@@ -58,7 +59,7 @@ export default connect(
return ( return (
<Popover content={popContent} visible={visibility}> <Popover content={popContent} visible={visibility}>
<Button onClick={() => setVisibility(true)}> <Button disabled={disabled} onClick={() => setVisibility(true)}>
{t("allocations.actions.assign")} {t("allocations.actions.assign")}
</Button> </Button>
</Popover> </Popover>

View File

@@ -37,6 +37,7 @@ export default function AllocationsBulkAssignmentContainer({
return ( return (
<AllocationsBulkAssignment <AllocationsBulkAssignment
disabled={jobLines.length > 0 ? false : true}
handleAssignment={handleAssignment} handleAssignment={handleAssignment}
assignment={assignment} assignment={assignment}
setAssignment={setAssignment} setAssignment={setAssignment}

View File

@@ -2,18 +2,14 @@ import { Button, Modal, notification } from "antd";
import axios from "axios"; import axios from "axios";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useLazyQuery } from "react-apollo"; import { useLazyQuery } from "react-apollo";
import { renderEmail } from "react-html-email"; import ReactDOMServer from "react-dom/server";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { toggleEmailOverlayVisible } from "../../redux/email/email.actions"; import { toggleEmailOverlayVisible } from "../../redux/email/email.actions";
import { import { selectEmailConfig, selectEmailVisible } from "../../redux/email/email.selectors.js";
selectEmailConfig,
selectEmailVisible
} from "../../redux/email/email.selectors.js";
import LoadingSpinner from "../loading-spinner/loading-spinner.component"; import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import EmailOverlayComponent from "./email-overlay.component"; import EmailOverlayComponent from "./email-overlay.component";
import ReactDOMServer from "react-dom/server";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
modalVisible: selectEmailVisible, modalVisible: selectEmailVisible,

View File

@@ -8,6 +8,7 @@ import { Link } from "react-router-dom";
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 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";
export default function JobLinesComponent({ export default function JobLinesComponent({
loading, loading,
refetch, refetch,
@@ -16,7 +17,9 @@ export default function JobLinesComponent({
selectedLines, selectedLines,
setSelectedLines, setSelectedLines,
partsOrderModalVisible, partsOrderModalVisible,
jobId jobId,
editLineModalVisible,
lineToEdit
}) { }) {
const [state, setState] = useState({ const [state, setState] = useState({
sortedInfo: {} sortedInfo: {}
@@ -45,7 +48,8 @@ export default function JobLinesComponent({
sortOrder: sortOrder:
state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order, state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
ellipsis: true, ellipsis: true,
editable: true editable: true,
width: "20%"
}, },
{ {
title: t("joblines.fields.oem_partno"), title: t("joblines.fields.oem_partno"),
@@ -60,7 +64,7 @@ export default function JobLinesComponent({
state.sortedInfo.columnKey === "oem_partno" && state.sortedInfo.order, state.sortedInfo.columnKey === "oem_partno" && state.sortedInfo.order,
ellipsis: true, ellipsis: true,
editable: true, editable: true,
width: "20%", width: "10%",
render: (text, record) => ( render: (text, record) => (
<span> <span>
{record.oem_partno ? record.oem_partno : record.op_code_desc} {record.oem_partno ? record.oem_partno : record.op_code_desc}
@@ -76,7 +80,15 @@ export default function JobLinesComponent({
state.sortedInfo.columnKey === "part_type" && state.sortedInfo.order, state.sortedInfo.columnKey === "part_type" && state.sortedInfo.order,
ellipsis: true, ellipsis: true,
editable: true, editable: true,
width: "10%" width: "7%"
},
{
title: t("joblines.fields.line_ind"),
dataIndex: "line_ind",
key: "line_ind",
sorter: (a, b) => alphaSort(a.line_ind, b.line_ind),
sortOrder:
state.sortedInfo.columnKey === "line_ind" && state.sortedInfo.order
}, },
{ {
title: t("joblines.fields.db_price"), title: t("joblines.fields.db_price"),
@@ -86,7 +98,7 @@ export default function JobLinesComponent({
sortOrder: sortOrder:
state.sortedInfo.columnKey === "db_price" && state.sortedInfo.order, state.sortedInfo.columnKey === "db_price" && state.sortedInfo.order,
ellipsis: true, ellipsis: true,
width: "10%", width: "8%",
render: (text, record) => ( render: (text, record) => (
<CurrencyFormatter>{record.db_price}</CurrencyFormatter> <CurrencyFormatter>{record.db_price}</CurrencyFormatter>
) )
@@ -99,7 +111,7 @@ export default function JobLinesComponent({
sortOrder: sortOrder:
state.sortedInfo.columnKey === "act_price" && state.sortedInfo.order, state.sortedInfo.columnKey === "act_price" && state.sortedInfo.order,
ellipsis: true, ellipsis: true,
width: "10%", width: "8%",
render: (text, record) => ( render: (text, record) => (
<CurrencyFormatter>{record.act_price}</CurrencyFormatter> <CurrencyFormatter>{record.act_price}</CurrencyFormatter>
) )
@@ -124,6 +136,7 @@ export default function JobLinesComponent({
title: t("allocations.fields.employee"), title: t("allocations.fields.employee"),
dataIndex: "employee", dataIndex: "employee",
key: "employee", key: "employee",
width: "10%",
sorter: (a, b) => a.act_price - b.act_price, //TODO Fix employee sorting. sorter: (a, b) => a.act_price - b.act_price, //TODO Fix employee sorting.
sortOrder: sortOrder:
state.sortedInfo.columnKey === "employee" && state.sortedInfo.order, state.sortedInfo.columnKey === "employee" && state.sortedInfo.order,
@@ -152,7 +165,13 @@ export default function JobLinesComponent({
key: "actions", key: "actions",
render: (text, record) => ( render: (text, record) => (
<span> <span>
<Button>{t("general.actions.edit")}</Button> <Button
onClick={() => {
lineToEdit[1](record);
editLineModalVisible[1](true);
}}>
{t("general.actions.edit")}
</Button>
</span> </span>
) )
} }
@@ -175,14 +194,20 @@ export default function JobLinesComponent({
return ( return (
<div> <div>
{partsOrderModalVisible[0] ? ( <PartsOrderModalContainer
<PartsOrderModalContainer partsOrderModalVisible={partsOrderModalVisible}
partsOrderModalVisible={partsOrderModalVisible} linesToOrder={selectedLines}
linesToOrder={selectedLines} refetch={refetch}
refetch={refetch} jobId={jobId}
jobId={jobId} />
/>
) : null} <JobLineUpsertModalContainer
jobId={jobId}
visible={editLineModalVisible[0]}
changeVisibility={editLineModalVisible[1]}
refetch={refetch}
existingLine={lineToEdit[0]}
/>
<Table <Table
title={() => { title={() => {

View File

@@ -16,6 +16,9 @@ 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 (
@@ -58,6 +61,8 @@ export default function JobLinesContainer({ jobId }) {
setSelectedLines={setSelectedLines} setSelectedLines={setSelectedLines}
partsOrderModalVisible={partsOrderModalVisible} partsOrderModalVisible={partsOrderModalVisible}
jobId={jobId} jobId={jobId}
editLineModalVisible={editLineModalVisible}
lineToEdit={lineToEdit}
/> />
); );
} }

View File

@@ -0,0 +1,33 @@
import { Input, Modal } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
export default function JobLinesUpsertModalComponent({
visible,
changeVisibility,
lineState,
setLineState,
updateExistingLine,
insertNewLine
}) {
const { t } = useTranslation();
const handleChange = e => {
setLineState({ ...lineState, [e.target.name]: e.target.value });
};
return (
<Modal
title={
lineState.id ? t("joblines.actions.edit") : t("joblines.actions.new")
}
visible={visible}
okText={t("general.labels.save")}
onOk={() => {
lineState.id ? updateExistingLine() : insertNewLine();
}}
onCancel={() => {
changeVisibility(false);
}}>
<Input.TextArea rows={8} value={lineState.text} onChange={handleChange} />
</Modal>
);
}

View File

@@ -0,0 +1,72 @@
import { notification } from "antd";
import React, { useEffect, useState } from "react";
import { useMutation } from "react-apollo";
import { useTranslation } from "react-i18next";
import {
INSERT_NEW_JOB_LINE,
UPDATE_JOB_LINE
} from "../../graphql/jobs-lines.queries";
import JobLinesUpdsertModal from "./job-lines-upsert-modal.component";
export default function JobLinesUpsertModalContainer({
jobId,
visible,
changeVisibility,
refetch,
existingLine
}) {
const { t } = useTranslation();
const [insertJobLine] = useMutation(INSERT_NEW_JOB_LINE);
const [updateJobLine] = useMutation(UPDATE_JOB_LINE);
const [lineState, setLineState] = useState({});
useEffect(() => {
//Required to prevent infinite looping.
if (existingLine) {
setLineState(existingLine);
}
}, [existingLine]);
const insertNewLine = () => {
insertJobLine({
variables: {
lineInput: [{ ...lineState, jobid: jobId }]
}
}).then(r => {
refetch();
changeVisibility(!visible);
notification["success"]({
message: t("joblines.successes.create")
});
});
};
const updateExistingLine = () => {
//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")
});
});
refetch();
changeVisibility(!visible);
};
console.log("lineSTate", lineState);
return (
<JobLinesUpdsertModal
visible={visible}
changeVisibility={changeVisibility}
updateExistingLine={updateExistingLine}
insertNewLine={insertNewLine}
lineState={lineState}
setLineState={setLineState}
/>
);
}

View File

@@ -5,12 +5,20 @@ import { useTranslation } from "react-i18next";
import { INSERT_NEW_NOTE, UPDATE_NOTE } from "../../graphql/notes.queries"; import { INSERT_NEW_NOTE, UPDATE_NOTE } from "../../graphql/notes.queries";
import NoteUpsertModalComponent from "./note-upsert-modal.component"; import NoteUpsertModalComponent from "./note-upsert-modal.component";
export default function NoteUpsertModalContainer({
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectCurrentUser } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser
});
export default connect (mapStateToProps,null)( function NoteUpsertModalContainer({
jobId, jobId,
visible, visible,
changeVisibility, changeVisibility,
refetch, refetch,
existingNote existingNote,currentUser
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [insertNote] = useMutation(INSERT_NEW_NOTE); const [insertNote] = useMutation(INSERT_NEW_NOTE);
@@ -33,7 +41,7 @@ export default function NoteUpsertModalContainer({
insertNote({ insertNote({
variables: { variables: {
noteInput: [ noteInput: [
{ ...noteState, jobid: jobId, created_by: "patrick@bodyshop.app" } //TODO Fix the created by. { ...noteState, jobid: jobId, created_by: currentUser.email }
] ]
} }
}).then(r => { }).then(r => {
@@ -73,3 +81,4 @@ export default function NoteUpsertModalContainer({
/> />
); );
} }
);

View File

@@ -52,3 +52,22 @@ export const UPDATE_JOB_LINE_STATUS = gql`
} }
} }
`; `;
export const INSERT_NEW_JOB_LINE = gql`
mutation INSERT_NEW_JOB_LINE($lineInput: [joblines_insert_input!]!) {
insert_joblines(objects: $lineInput) {
returning {
id
}
}
}
`;
export const UPDATE_JOB_LINE = gql`
mutation UPDATE_JOB_LINE($lineId: uuid!, $line: joblines_set_input!) {
update_joblines(where: { id: { _eq: $lineId } }, _set: $line) {
returning {
id
}
}
}
`;

View File

@@ -140,6 +140,7 @@
"act_price": "Actual Price", "act_price": "Actual Price",
"db_price": "Database Price", "db_price": "Database Price",
"line_desc": "Line Description", "line_desc": "Line Description",
"line_ind": "S#",
"mod_lb_hrs": "Labor Hours", "mod_lb_hrs": "Labor Hours",
"oem_partno": "OEM Part #", "oem_partno": "OEM Part #",
"part_type": "Part Type", "part_type": "Part Type",

View File

@@ -140,6 +140,7 @@
"act_price": "Precio actual", "act_price": "Precio actual",
"db_price": "Precio de base de datos", "db_price": "Precio de base de datos",
"line_desc": "Descripción de línea", "line_desc": "Descripción de línea",
"line_ind": "S#",
"mod_lb_hrs": "Horas laborales", "mod_lb_hrs": "Horas laborales",
"oem_partno": "OEM parte #", "oem_partno": "OEM parte #",
"part_type": "Tipo de parte", "part_type": "Tipo de parte",

View File

@@ -140,6 +140,7 @@
"act_price": "Prix actuel", "act_price": "Prix actuel",
"db_price": "Prix de la base de données", "db_price": "Prix de la base de données",
"line_desc": "Description de la ligne", "line_desc": "Description de la ligne",
"line_ind": "S#",
"mod_lb_hrs": "Heures de travail", "mod_lb_hrs": "Heures de travail",
"oem_partno": "Pièce OEM #", "oem_partno": "Pièce OEM #",
"part_type": "Type de pièce", "part_type": "Type de pièce",

View File

@@ -2,10 +2,7 @@ export function alphaSort(a, b) {
let A; let A;
let B; let B;
A = a ? a.toLowerCase() : ""; A = a ? a.toLowerCase() : "";
B = b ? b.toLowerCase() : ""; B = b ? b.toLowerCase() : "";
console.log("Objects", A, B, A < B, A > B);
if (A < B) if (A < B)
//sort string ascending //sort string ascending
return -1; return -1;