Updated UI and added tech elements.

This commit is contained in:
Patrick Fic
2023-07-21 13:40:39 -07:00
parent 8dfcda6c5e
commit 7b49a94edd
14 changed files with 210 additions and 33 deletions

View File

@@ -33996,6 +33996,27 @@
<folder_node>
<name>tech</name>
<children>
<concept_node>
<name>claimtask</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>
<name>home</name>
<definition_loaded>false</definition_loaded>
@@ -46950,6 +46971,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>unassigned</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>
<name>zeroactualnegativeprod</name>
<definition_loaded>false</definition_loaded>
@@ -47149,6 +47191,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>unassignedlines</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>
</folder_node>
</children>

View File

@@ -30,10 +30,6 @@ export function JoblineBulkAssign({
job,
currentUser,
}) {
console.log(
"🚀 ~ file: job-line-bulk-assign.component.jsx:36 ~ selectedLines:",
selectedLines
);
const [visible, setVisible] = useState(false);
const [loading, setLoading] = useState(false);
const [form] = Form.useForm();

View File

@@ -61,7 +61,11 @@ export function PayrollLaborAllocationsTable({
key: "employeeid",
render: (text, record) => {
if (record.employeeid === undefined) {
return "Unassigned";
return (
<span style={{ color: "tomato", fontWeight: "bolder" }}>
{t("timetickets.labels.unassigned")}
</span>
);
}
const emp = bodyshop.employees.find((e) => e.id === record.employeeid);
return `${emp?.first_name} ${emp?.last_name}`;
@@ -71,12 +75,20 @@ export function PayrollLaborAllocationsTable({
title: t("joblines.fields.mod_lbr_ty"),
dataIndex: "mod_lbr_ty",
key: "mod_lbr_ty",
render: (text, record) =>
record.employeeid === undefined ? (
<span style={{ color: "tomato", fontWeight: "bolder" }}>
{t("timetickets.labels.unassigned")}
</span>
) : (
t(`joblines.fields.lbr_types.${record.mod_lbr_ty?.toUpperCase()}`)
),
},
{
title: t("timetickets.fields.rate"),
dataIndex: "rate",
key: "rate",
},
// {
// title: t("timetickets.fields.rate"),
// dataIndex: "rate",
// key: "rate",
// },
{
title: t("jobs.labels.hrs_total"),
dataIndex: "expectedHours",
@@ -251,7 +263,6 @@ export function PayrollLaborAllocationsTable({
</Typography.Title>
</Table.Summary.Cell>
<Table.Summary.Cell></Table.Summary.Cell>
<Table.Summary.Cell></Table.Summary.Cell>
<Table.Summary.Cell>
{summary.hrs_total.toFixed(5)}
</Table.Summary.Cell>

View File

@@ -24,6 +24,8 @@ import ProductionListColumnNote from "./production-list-columns.productionnote.c
import ProductionListColumnCategory from "./production-list-columns.status.category";
import ProductionListColumnStatus from "./production-list-columns.status.component";
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
import { store } from "../../redux/store";
import { setModalContext } from "../../redux/modals/modals.actions";
const r = ({ technician, state, activeStatuses, bodyshop }) => {
return [
@@ -38,6 +40,29 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
</Link>
),
},
{
title: i18n.t("timetickets.actions.claimtasks"),
dataIndex: "claimtasks",
key: "claimtasks",
ellipsis: true,
render: (text, record) => (
<div
onClick={() => {
store.dispatch(
setModalContext({
context: {
actions: {},
context: { jobid: record.id },
},
modal: "timeTicketTask",
})
);
}}
>
{i18n.t("timetickets.actions.claimtasks")}
</div>
),
},
{
title: i18n.t("jobs.fields.ro_number"),
dataIndex: "ro_number",

View File

@@ -11,22 +11,38 @@ import { createStructuredSelector } from "reselect";
import { techLogout } from "../../redux/tech/tech.actions";
import { selectTechnician } from "../../redux/tech/tech.selectors";
import { BsKanban } from "react-icons/bs";
import { useTreatments } from "@splitsoftware/splitio-react";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { setModalContext } from "../../redux/modals/modals.actions";
const { Sider } = Layout;
const mapStateToProps = createStructuredSelector({
technician: selectTechnician,
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
techLogout: () => dispatch(techLogout()),
setTimeTicketTaskContext: (context) =>
dispatch(setModalContext({ context: context, modal: "timeTicketTask" })),
});
export function TechSider({ technician, techLogout }) {
export function TechSider({
technician,
techLogout,
bodyshop,
setTimeTicketTaskContext,
}) {
const [collapsed, setCollapsed] = useState(true);
const { t } = useTranslation();
const onCollapse = (collapsed) => {
setCollapsed(collapsed);
};
const { Enhanced_Payroll } = useTreatments(
["Enhanced_Payroll"],
{},
bodyshop.imexshopid
);
return (
<Sider
@@ -51,13 +67,29 @@ export function TechSider({ technician, techLogout }) {
<Menu.Item key="2" disabled={!!!technician} icon={<SearchOutlined />}>
<Link to={`/tech/joblookup`}>{t("menus.tech.joblookup")}</Link>
</Menu.Item>
<Menu.Item
key="3"
disabled={!!!technician}
icon={<Icon component={FaBusinessTime} />}
>
<Link to={`/tech/jobclock`}>{t("menus.tech.jobclockin")}</Link>
</Menu.Item>
{Enhanced_Payroll.treatment === "on" ? (
<Menu.Item
key="3"
disabled={!!!technician}
icon={<Icon component={FaBusinessTime} />}
onClick={() => {
setTimeTicketTaskContext({
actions: {},
context: { jobid: null },
});
}}
>
{t("menus.tech.claimtask")}
</Menu.Item>
) : (
<Menu.Item
key="3"
disabled={!!!technician}
icon={<Icon component={FaBusinessTime} />}
>
<Link to={`/tech/jobclock`}>{t("menus.tech.jobclockin")}</Link>
</Menu.Item>
)}
<Menu.Item
key="4"
disabled={!!!technician}

View File

@@ -34,7 +34,12 @@ export function TimeTicketTaskModalComponent({
form,
loading,
completedTasks,
unassignedHours,
}) {
console.log(
"🚀 ~ file: time-ticket-task-modal.component.jsx:39 ~ unassignedHours:",
unassignedHours
);
const { t } = useTranslation();
return (
@@ -80,7 +85,7 @@ export function TimeTicketTaskModalComponent({
if (!task) return null;
return (
<table className="bill-inventory-table">
<table className="task-tickets-table">
<tbody>
<tr>
<td>{t("bodyshop.fields.md_tasks_presets.percent")}</td>
@@ -116,7 +121,7 @@ export function TimeTicketTaskModalComponent({
<Typography.Title level={4}>
{t("timetickets.labels.claimtaskpreview")}
</Typography.Title>
<table className="bill-cm-returns-table">
<table className="task-tickets-table">
<thead>
<tr>
<th>{t("timetickets.fields.employee")}</th>
@@ -173,6 +178,14 @@ export function TimeTicketTaskModalComponent({
}}
</Form.List>
)}
{unassignedHours > 0 && (
<Alert
type="error"
message={t("timetickets.validation.unassignedlines", {
unassignedHours: unassignedHours,
})}
/>
)}
</Col>
</Row>

View File

@@ -11,6 +11,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
import TimeTicketTaskModalComponent from "./time-ticket-task-modal.component";
import { useApolloClient } from "@apollo/client";
import { QUERY_COMPLETED_TASKS } from "../../graphql/jobs.queries";
import "./time-ticket-task-modal.styles.scss";
const mapStateToProps = createStructuredSelector({
timeTicketTasksModal: selectTimeTicketTasks,
@@ -32,6 +33,7 @@ export function TimeTickeTaskModalContainer({
const [form] = Form.useForm();
const { context, visible } = timeTicketTasksModal;
const [completedTasks, setCompletedTasks] = useState([]);
const [unassignedHours, setUnassignedHours] = useState(0);
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const client = useApolloClient();
@@ -83,7 +85,8 @@ export function TimeTickeTaskModalContainer({
//Close the modal
toggleModalVisible();
} else if (handleFinish === false) {
form.setFieldsValue({ timetickets: data });
form.setFieldsValue({ timetickets: data.ticketsToInsert });
setUnassignedHours(data.unassignedHours);
} else {
notification.open({
type: "error",
@@ -125,6 +128,7 @@ export function TimeTickeTaskModalContainer({
form={form}
loading={loading}
completedTasks={completedTasks}
unassignedHours={unassignedHours}
/>
</Form>
</Modal>

View File

@@ -0,0 +1,19 @@
.task-tickets-table {
table-layout: fixed;
width: 100%;
th,
td {
padding: 8px;
text-align: left;
border-bottom: 1px solid #ddd;
.ant-form-item {
margin-bottom: 0px !important;
}
}
tr:hover {
background-color: #f5f5f5;
}
}

View File

@@ -35,7 +35,11 @@ const TechJobClock = lazy(() =>
const TechShiftClock = lazy(() =>
import("../tech-shift-clock/tech-shift-clock.component")
);
const TimeTicketModalTask = lazy(() =>
import(
"../../components/time-ticket-task-modal/time-ticket-task-modal.container"
)
);
const { Content } = Layout;
const mapStateToProps = createStructuredSelector({
@@ -70,6 +74,7 @@ export function TechPage({ technician, match }) {
<FeatureWrapper featureName="tech-console">
<TimeTicketModalContainer />
<PrintCenterModalContainer />
<TimeTicketModalTask />
<Switch>
<Route
exact

View File

@@ -1995,6 +1995,7 @@
"shops": "My Shops"
},
"tech": {
"claimtask": "Claim Task",
"home": "Home",
"jobclockin": "Job Clock In",
"jobclockout": "Job Clock Out",
@@ -2781,6 +2782,7 @@
"straight_time": "Straight Time",
"task": "Task",
"timetickets": "Time Tickets",
"unassigned": "Unassigned",
"zeroactualnegativeprod": "Actual hours must be 0 if entering negative productive hours."
},
"successes": {
@@ -2793,7 +2795,8 @@
"validation": {
"clockoffmustbeafterclockon": "Clock off time must be the same or after clock in time.",
"clockoffwithoutclockon": "Clock off time cannot be set without a clock in time.",
"hoursenteredmorethanavailable": "The number of hours entered is more than what is available for this cost center."
"hoursenteredmorethanavailable": "The number of hours entered is more than what is available for this cost center.",
"unassignedlines": "There are currently {{unassignedHours}} hours of repair lines that are unassigned. These hours are not including in the above calculations and must be paid manually."
}
},
"titles": {

View File

@@ -1995,6 +1995,7 @@
"shops": "Mis tiendas"
},
"tech": {
"claimtask": "",
"home": "",
"jobclockin": "",
"jobclockout": "",
@@ -2781,6 +2782,7 @@
"straight_time": "",
"task": "",
"timetickets": "",
"unassigned": "",
"zeroactualnegativeprod": ""
},
"successes": {
@@ -2793,7 +2795,8 @@
"validation": {
"clockoffmustbeafterclockon": "",
"clockoffwithoutclockon": "",
"hoursenteredmorethanavailable": ""
"hoursenteredmorethanavailable": "",
"unassignedlines": ""
}
},
"titles": {

View File

@@ -1995,6 +1995,7 @@
"shops": "Mes boutiques"
},
"tech": {
"claimtask": "",
"home": "",
"jobclockin": "",
"jobclockout": "",
@@ -2781,6 +2782,7 @@
"straight_time": "",
"task": "",
"timetickets": "",
"unassigned": "",
"zeroactualnegativeprod": ""
},
"successes": {
@@ -2793,7 +2795,8 @@
"validation": {
"clockoffmustbeafterclockon": "",
"clockoffwithoutclockon": "",
"hoursenteredmorethanavailable": ""
"hoursenteredmorethanavailable": "",
"unassignedlines": ""
}
},
"titles": {

View File

@@ -33,7 +33,7 @@ exports.claimtask = async function (req, res) {
);
//Get all of the assignments that are filtered.
const { employeeHash } = CalculateExpectedHoursForJob(
const { assignmentHash, employeeHash } = CalculateExpectedHoursForJob(
job,
theTaskPreset.hourstype
);
@@ -83,7 +83,7 @@ exports.claimtask = async function (req, res) {
},
});
}
res.json(ticketsToInsert);
res.json({ unassignedHours: assignmentHash.unassigned, ticketsToInsert });
} catch (error) {
logger.log("job-payroll-claim-task-error", "ERROR", req.user.email, jobid, {
jobid: jobid,

View File

@@ -62,7 +62,7 @@ exports.payall = async function (req, res) {
cost_center:
job.bodyshop.md_responsibility_centers.defaults.costs[key],
flat_rate: true,
memo: "*System* Hours added during Pay All function. (multi)",
memo: `*SYS-PAY* Add unclaimed hours. (${req.user.email})`,
});
});
} else {
@@ -79,7 +79,7 @@ exports.payall = async function (req, res) {
job.bodyshop.md_responsibility_centers.defaults.costs[
path.mod_lbr_ty
],
memo: "*System* Hours added during Pay All function.",
memo: `*SYS-PAY* Add unclaimed hours. (${req.user.email})`,
});
}
} else if (diff.op === "update") {
@@ -97,7 +97,7 @@ exports.payall = async function (req, res) {
job.bodyshop.md_responsibility_centers.defaults.costs[
path.mod_lbr_ty
],
memo: "*System* Hours adjustment during Pay All function. (Update)",
memo: `*SYS-PAY* Adjust claimed hours per assignment. (${req.user.email})`,
});
} else {
//Has to be a delete
@@ -123,7 +123,7 @@ exports.payall = async function (req, res) {
cost_center:
job.bodyshop.md_responsibility_centers.defaults.costs[key],
flat_rate: true,
memo: "*System* Hours removed during Pay All function. (Change in rate, unassignment, etc.) *multi*",
memo: `*SYS-PAY* Remove claimed hours per assignment. (${req.user.email})`,
});
});
} else {
@@ -140,7 +140,7 @@ exports.payall = async function (req, res) {
path.mod_lbr_ty
],
flat_rate: true,
memo: "*System* Hours removed during Pay All function. (Change in rate, unassignment, etc.)",
memo: `*SYS-PAY* Remove claimed hours per assignment. (${req.user.email})`,
});
}
}