BOD-21 Further customization of components. Added remove to header. Altered colum adding to use button instead of transfer

This commit is contained in:
Patrick Fic
2020-04-22 14:43:37 -07:00
parent 400dfabcec
commit 678f09b47a
14 changed files with 340 additions and 102 deletions

View File

@@ -8184,27 +8184,6 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>bodyhours</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>
<folder_node> <folder_node>
<name>cards</name> <name>cards</name>
<children> <children>
@@ -8871,27 +8850,6 @@
</concept_node> </concept_node>
</children> </children>
</folder_node> </folder_node>
<concept_node>
<name>refinishhours</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>vehicle_info</name> <name>vehicle_info</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -11074,6 +11032,27 @@
<folder_node> <folder_node>
<name>actions</name> <name>actions</name>
<children> <children>
<concept_node>
<name>addcolumns</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>bodypriority-clear</name> <name>bodypriority-clear</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -11158,6 +11137,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>removecolumn</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>saveconfig</name> <name>saveconfig</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -11247,6 +11247,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>bodyhours</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>bodypriority</name> <name>bodypriority</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -11331,6 +11352,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>refinishhours</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>
</children> </children>
</folder_node> </folder_node>
</children> </children>

View File

@@ -4,7 +4,7 @@ import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { selectBreadcrumbs } from "../../redux/application/application.selectors"; import { selectBreadcrumbs } from "../../redux/application/application.selectors";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { HomeFilled } from "@ant-design/icons";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
breadcrumbs: selectBreadcrumbs, breadcrumbs: selectBreadcrumbs,
}); });
@@ -12,7 +12,11 @@ const mapStateToProps = createStructuredSelector({
export function BreadCrumbs({ breadcrumbs }) { export function BreadCrumbs({ breadcrumbs }) {
return ( return (
<Breadcrumb> <Breadcrumb>
<Breadcrumb.Item>Home</Breadcrumb.Item> <Breadcrumb.Item>
<Link to={`/manage`}>
<HomeFilled />
</Link>
</Breadcrumb.Item>
{breadcrumbs.map((item) => {breadcrumbs.map((item) =>
item.link ? ( item.link ? (
<Breadcrumb.Item key={item.label}> <Breadcrumb.Item key={item.label}>

View File

@@ -0,0 +1,41 @@
import React from "react";
import { Button, Dropdown, Menu } from "antd";
import dataSource from "./production-list-columns.data";
import { useTranslation } from "react-i18next";
export default function ProductionColumnsComponent({ columnState }) {
const [columns, setColumns] = columnState;
const { t } = useTranslation();
const handleAdd = (e) => {
setColumns([...columns, ...dataSource.filter((i) => i.key === e.key)]);
};
const columnKeys = columns.map((i) => i.key);
const menu = (
<Menu onClick={handleAdd}>
{dataSource
.filter((i) => !columnKeys.includes(i.key))
.map((item) => (
<Menu.Item key={item.key}>{item.title}</Menu.Item>
))}
</Menu>
);
return (
<div>
<Dropdown overlay={menu}>
<Button>{t("production.actions.addcolumns")}</Button>
</Dropdown>
</div>
);
}
// <Transfer
// dataSource={dataSource}
// titles={["Source", "Target"]}
// targetKeys={columns.map((c) => c.key)}
// render={(item) => item.title}
// onChange={(nextTargetKeys, direction, moveKeys) => {
// setColumns(dataSource.filter((i) => nextTargetKeys.includes(i.key)));
// }}
// />

View File

@@ -1,22 +0,0 @@
import React from "react";
import { Transfer } from "antd";
import dataSource from "./production-list-columns.data";
export default function ProductionColumnsComponent({ columnState }) {
const [columns, setColumns] = columnState;
return (
<div>
<Transfer
dataSource={dataSource}
titles={["Source", "Target"]}
targetKeys={columns.map((c) => c.key)}
render={(item) => item.title}
onChange={(nextTargetKeys, direction, moveKeys) => {
setColumns(dataSource.filter((i) => nextTargetKeys.includes(i.key)));
}}
/>
</div>
);
}

View File

@@ -8,6 +8,8 @@ import { alphaSort } from "../../utils/sorters";
import ProductionListColumnAlert from "./production-list-columns.alert.component"; import ProductionListColumnAlert from "./production-list-columns.alert.component";
import ProductionListColumnBodyPriority from "./production-list-columns.bodypriority.component"; import ProductionListColumnBodyPriority from "./production-list-columns.bodypriority.component";
import ProductionListColumnPaintPriority from "./production-list-columns.paintpriority.component"; import ProductionListColumnPaintPriority from "./production-list-columns.paintpriority.component";
import ProductionListColumnStatus from "./production-list-columns.status.component";
import ProductionListColumnNote from "./production-list-columns.productionnote.component";
export default [ export default [
{ {
@@ -135,15 +137,16 @@ export default [
key: "status", key: "status",
ellipsis: true, ellipsis: true,
sorter: (a, b) => alphaSort(a.status, b.status), sorter: (a, b) => alphaSort(a.status, b.status),
render: (text, record) => <ProductionListColumnStatus record={record} />,
}, },
{ {
title: i18n.t("jobs.labels.bodyhours"), title: i18n.t("production.labels.bodyhours"),
dataIndex: "labhrs", dataIndex: "labhrs",
key: "labhrs", key: "labhrs",
sorter: (a, b) => a.labhrs - b.labhrs, sorter: (a, b) => a.labhrs - b.labhrs,
}, },
{ {
title: i18n.t("jobs.labels.refinishhours"), title: i18n.t("production.labels.refinishhours"),
dataIndex: "larhrs", dataIndex: "larhrs",
key: "larhrs", key: "larhrs",
sorter: (a, b) => a.larhrs - b.larhrs, sorter: (a, b) => a.larhrs - b.larhrs,
@@ -158,11 +161,8 @@ export default [
title: i18n.t("production.labels.note"), title: i18n.t("production.labels.note"),
dataIndex: "note", dataIndex: "note",
key: "note", key: "note",
render: (text, record) => ( ellipsis: true,
<span> render: (text, record) => <ProductionListColumnNote record={record} />,
{(record.production_vars && record.production_vars.note) || ""}
</span>
),
}, },
{ {
title: i18n.t("production.labels.cycletime"), title: i18n.t("production.labels.cycletime"),

View File

@@ -0,0 +1,72 @@
import { useMutation } from "@apollo/react-hooks";
import { Button, Input, Popover } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { UPDATE_JOB } from "../../graphql/jobs.queries";
export default function ProductionListColumnProductionNote({ record }) {
const { t } = useTranslation();
const [note, setNote] = useState(
(record.production_vars && record.production_vars.note) || ""
);
const [visible, setVisible] = useState(false);
const [updateAlert] = useMutation(UPDATE_JOB);
const handleSaveNote = (e) => {
setVisible(false);
updateAlert({
variables: {
jobId: record.id,
job: {
production_vars: {
...record.production_vars,
note: note,
},
},
},
}).then(() => {
if (record.refetch) record.refetch();
});
};
const handleChange = (e) => {
setNote(e.target.value);
};
const handleVisibleChange = (flag) => {
setVisible(flag);
if (flag)
setNote((record.production_vars && record.production_vars.note) || "");
};
return (
<Popover
onVisibleChange={handleVisibleChange}
visible={visible}
content={
<div style={{ width: "30em" }}>
<Input.TextArea
rows={2}
value={note}
onChange={handleChange}
onPressEnter={handleSaveNote}
autoFocus
allowClear
/>
<div>
<Button onClick={handleSaveNote}>
{t("general.actions.save")}
</Button>
</div>
</div>
}
trigger={["contextMenu"]}>
<div style={{ width: "100%", height: "19px" }}>
{(record.production_vars && record.production_vars.note) || " "}
</div>
</Popover>
);
}

View File

@@ -0,0 +1,46 @@
import { useMutation } from "@apollo/react-hooks";
import { Dropdown, Menu } from "antd";
import React from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { UPDATE_JOB } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
export function ProductionListColumnStatus({ record, bodyshop }) {
const [updateJob] = useMutation(UPDATE_JOB);
const handleSetStatus = (e) => {
const { key } = e;
updateJob({
variables: {
jobId: record.id,
job: {
status: key,
},
},
}).then(() => {
if (record.refetch) record.refetch();
});
};
return (
<Dropdown
overlay={
<Menu
style={{ maxHeight: "200px", overflowY: "auto" }}
onClick={handleSetStatus}>
{bodyshop.md_ro_statuses.statuses.map((item) => (
<Menu.Item key={item}>{item}</Menu.Item>
))}
</Menu>
}
trigger={["contextMenu"]}>
<div style={{ width: "100%", height: "19px" }}>{record.status}</div>
</Dropdown>
);
}
export default connect(mapStateToProps, null)(ProductionListColumnStatus);

View File

@@ -1,4 +1,4 @@
import { Table, Button } from "antd"; import { Table, Button, Menu, Dropdown } from "antd";
import React, { useState } from "react"; import React, { useState } from "react";
import { SyncOutlined } from "@ant-design/icons"; import { SyncOutlined } from "@ant-design/icons";
import ProductionListSaveConfigButton from "../production-list-save-config-button/production-list-save-config-button.component"; import ProductionListSaveConfigButton from "../production-list-save-config-button/production-list-save-config-button.component";
@@ -7,6 +7,8 @@ import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import ReactDragListView from "react-drag-listview"; //TODO Is there a better way? This library is too big. import ReactDragListView from "react-drag-listview"; //TODO Is there a better way? This library is too big.
import "./production-list-table.styles.scss"; import "./production-list-table.styles.scss";
import { useTranslation } from "react-i18next";
import ProductionListColumnsAdd from "../production-list-columns/production-list-columns.add.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser //currentUser: selectCurrentUser
@@ -30,7 +32,7 @@ export function ProductionListTable({
filteredInfo: { text: "" }, filteredInfo: { text: "" },
} }
); );
const { t } = useTranslation();
const handleTableChange = (pagination, filters, sorter) => { const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter }); setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
}; };
@@ -42,6 +44,24 @@ export function ProductionListTable({
setColumns(columnsCopy); setColumns(columnsCopy);
}; };
const removeColumn = (e) => {
const { key } = e;
setColumns(columns.filter((i) => i.key !== key));
};
const headerItem = (col) => (
<Dropdown
overlay={
<Menu onClick={removeColumn}>
<Menu.Item key={col.key}>
{t("production.actions.removecolumn")}
</Menu.Item>
</Menu>
}
trigger={["contextMenu"]}>
<span>{col.title}</span>
</Dropdown>
);
if (!!!columns) return <div>No columns found.</div>; if (!!!columns) return <div>No columns found.</div>;
return ( return (
@@ -50,22 +70,26 @@ export function ProductionListTable({
size='small' size='small'
pagination={false} pagination={false}
title={() => ( title={() => (
<div> <div style={{ display: "flex" }}>
<ProductionListColumnsAdd columnState={columnState} />
<ProductionListSaveConfigButton <ProductionListSaveConfigButton
columns={columns} columns={columns}
tableState={state} tableState={state}
/> />
<Button onClick={() => refetch()}> <Button
onClick={() => {
if (refetch) refetch();
}}>
<SyncOutlined /> <SyncOutlined />
</Button> </Button>
</div> </div>
)} )}
pagination={{ position: "top" }}
columns={columns.map((c) => { columns={columns.map((c) => {
return { return {
...c, ...c,
sortOrder: sortOrder:
state.sortedInfo.columnKey === c.key && state.sortedInfo.order, state.sortedInfo.columnKey === c.key && state.sortedInfo.order,
title: headerItem(c),
}; };
})} })}
rowKey='id' rowKey='id'

View File

@@ -1,21 +1,23 @@
import { useQuery } from "@apollo/react-hooks"; import { useSubscription } from "@apollo/react-hooks";
import React from "react"; import React from "react";
import { QUERY_JOBS_IN_PRODUCTION } from "../../graphql/jobs.queries"; import { SUBSCRIPTION_JOBS_IN_PRODUCTION } from "../../graphql/jobs.queries";
import ProductionListTable from "./production-list-table.component"; import ProductionListTable from "./production-list-table.component";
export default function ProductionListTableContainer({ columnState }) { export default function ProductionListTableContainer({ columnState }) {
const { loading, data, refetch } = useQuery(QUERY_JOBS_IN_PRODUCTION, { // const { loading, data, refetch } = useQuery(QUERY_JOBS_IN_PRODUCTION, {
pollInterval: 30000, // pollInterval: 30000,
}); // });
const { loading, data } = useSubscription(SUBSCRIPTION_JOBS_IN_PRODUCTION);
return ( return (
<div>
<ProductionListTable <ProductionListTable
loading={loading} loading={loading}
data={data ? data.productionview : []} data={data ? data.productionview : []}
refetch={refetch} refetch={null}
columnState={columnState} columnState={columnState}
/> />
</div>
); );
} }

View File

@@ -79,6 +79,35 @@ export const QUERY_JOBS_IN_PRODUCTION = gql`
} }
`; `;
export const SUBSCRIPTION_JOBS_IN_PRODUCTION = gql`
subscription SUBSCRIPTION_JOBS_IN_PRODUCTION {
productionview {
id
status
ro_number
est_number
ownr_fn
ownr_ln
v_model_yr
v_model_desc
clm_no
v_make_desc
v_color
plate_no
actual_in
scheduled_completion
scheduled_delivery
ins_co_nm
clm_total
ownr_ph1
special_coverage_policy
production_vars
labhrs
larhrs
}
}
`;
export const GET_JOB_BY_PK = gql` export const GET_JOB_BY_PK = gql`
query GET_JOB_BY_PK($id: uuid!) { query GET_JOB_BY_PK($id: uuid!) {
jobs_by_pk(id: $id) { jobs_by_pk(id: $id) {

View File

@@ -1,12 +1,6 @@
import React from "react"; import React from "react";
import ProductionListColumns from "../../components/production-list-columns/production-list-columns.component";
import ProductionListTable from "../../components/production-list-table/production-list-table.container"; import ProductionListTable from "../../components/production-list-table/production-list-table.container";
export default function ProductionListComponent({ columnState }) { export default function ProductionListComponent({ columnState }) {
return ( return <ProductionListTable columnState={columnState} />;
<div>
<ProductionListColumns columnState={columnState} />
<ProductionListTable columnState={columnState} />
</div>
);
} }

View File

@@ -528,7 +528,6 @@
"audit": "Audit Trail", "audit": "Audit Trail",
"availablenew": "Available New Jobs", "availablenew": "Available New Jobs",
"availablesupplements": "Available Supplements", "availablesupplements": "Available Supplements",
"bodyhours": "Body Hrs",
"cards": { "cards": {
"appraiser": "Appraiser", "appraiser": "Appraiser",
"customer": "Customer Information", "customer": "Customer Information",
@@ -566,7 +565,6 @@
"ratetotals": { "ratetotals": {
"lab": "Body Total" "lab": "Body Total"
}, },
"refinishhours": "Refinish Hrs",
"vehicle_info": "Vehicle" "vehicle_info": "Vehicle"
}, },
"successes": { "successes": {
@@ -722,20 +720,24 @@
}, },
"production": { "production": {
"actions": { "actions": {
"addcolumns": "Add Columns",
"bodypriority-clear": "Clear Body Priority", "bodypriority-clear": "Clear Body Priority",
"bodypriority-set": "Set Body Priority", "bodypriority-set": "Set Body Priority",
"paintpriority-clear": "Clear Paint Priority", "paintpriority-clear": "Clear Paint Priority",
"paintpriority-set": "Set Paint Priority", "paintpriority-set": "Set Paint Priority",
"removecolumn": "Remove Column",
"saveconfig": "Save Configuration" "saveconfig": "Save Configuration"
}, },
"labels": { "labels": {
"alert": "Alert", "alert": "Alert",
"alertoff": "Remove alert from job", "alertoff": "Remove alert from job",
"alerton": "Add alert to job", "alerton": "Add alert to job",
"bodyhours": "B",
"bodypriority": "B/P", "bodypriority": "B/P",
"cycletime": "C/T", "cycletime": "C/T",
"note": "Production Note", "note": "Production Note",
"paintpriority": "P/P" "paintpriority": "P/P",
"refinishhours": "R"
} }
}, },
"profile": { "profile": {

View File

@@ -528,7 +528,6 @@
"audit": "", "audit": "",
"availablenew": "", "availablenew": "",
"availablesupplements": "", "availablesupplements": "",
"bodyhours": "",
"cards": { "cards": {
"appraiser": "Tasador", "appraiser": "Tasador",
"customer": "Información al cliente", "customer": "Información al cliente",
@@ -566,7 +565,6 @@
"ratetotals": { "ratetotals": {
"lab": "" "lab": ""
}, },
"refinishhours": "",
"vehicle_info": "Vehículo" "vehicle_info": "Vehículo"
}, },
"successes": { "successes": {
@@ -722,20 +720,24 @@
}, },
"production": { "production": {
"actions": { "actions": {
"addcolumns": "",
"bodypriority-clear": "", "bodypriority-clear": "",
"bodypriority-set": "", "bodypriority-set": "",
"paintpriority-clear": "", "paintpriority-clear": "",
"paintpriority-set": "", "paintpriority-set": "",
"removecolumn": "",
"saveconfig": "" "saveconfig": ""
}, },
"labels": { "labels": {
"alert": "", "alert": "",
"alertoff": "", "alertoff": "",
"alerton": "", "alerton": "",
"bodyhours": "",
"bodypriority": "", "bodypriority": "",
"cycletime": "", "cycletime": "",
"note": "", "note": "",
"paintpriority": "" "paintpriority": "",
"refinishhours": ""
} }
}, },
"profile": { "profile": {

View File

@@ -528,7 +528,6 @@
"audit": "", "audit": "",
"availablenew": "", "availablenew": "",
"availablesupplements": "", "availablesupplements": "",
"bodyhours": "",
"cards": { "cards": {
"appraiser": "Expert", "appraiser": "Expert",
"customer": "Informations client", "customer": "Informations client",
@@ -566,7 +565,6 @@
"ratetotals": { "ratetotals": {
"lab": "" "lab": ""
}, },
"refinishhours": "",
"vehicle_info": "Véhicule" "vehicle_info": "Véhicule"
}, },
"successes": { "successes": {
@@ -722,20 +720,24 @@
}, },
"production": { "production": {
"actions": { "actions": {
"addcolumns": "",
"bodypriority-clear": "", "bodypriority-clear": "",
"bodypriority-set": "", "bodypriority-set": "",
"paintpriority-clear": "", "paintpriority-clear": "",
"paintpriority-set": "", "paintpriority-set": "",
"removecolumn": "",
"saveconfig": "" "saveconfig": ""
}, },
"labels": { "labels": {
"alert": "", "alert": "",
"alertoff": "", "alertoff": "",
"alerton": "", "alerton": "",
"bodyhours": "",
"bodypriority": "", "bodypriority": "",
"cycletime": "", "cycletime": "",
"note": "", "note": "",
"paintpriority": "" "paintpriority": "",
"refinishhours": ""
} }
}, },
"profile": { "profile": {