diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index d2287e1c5..163889ba4 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -33996,6 +33996,27 @@ tech + + claimtask + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + home false @@ -46950,6 +46971,27 @@ + + unassigned + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + zeroactualnegativeprod false @@ -47149,6 +47191,27 @@ + + unassignedlines + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + diff --git a/client/src/components/job-line-bulk-assign/job-line-bulk-assign.component.jsx b/client/src/components/job-line-bulk-assign/job-line-bulk-assign.component.jsx index de2734a36..9b7a3fa8d 100644 --- a/client/src/components/job-line-bulk-assign/job-line-bulk-assign.component.jsx +++ b/client/src/components/job-line-bulk-assign/job-line-bulk-assign.component.jsx @@ -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(); diff --git a/client/src/components/labor-allocations-table/labor-allocations-table.payroll.component.jsx b/client/src/components/labor-allocations-table/labor-allocations-table.payroll.component.jsx index 25da96b32..85cd0d560 100644 --- a/client/src/components/labor-allocations-table/labor-allocations-table.payroll.component.jsx +++ b/client/src/components/labor-allocations-table/labor-allocations-table.payroll.component.jsx @@ -61,7 +61,11 @@ export function PayrollLaborAllocationsTable({ key: "employeeid", render: (text, record) => { if (record.employeeid === undefined) { - return "Unassigned"; + return ( + + {t("timetickets.labels.unassigned")} + + ); } 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 ? ( + + {t("timetickets.labels.unassigned")} + + ) : ( + 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({ - {summary.hrs_total.toFixed(5)} diff --git a/client/src/components/production-list-columns/production-list-columns.data.js b/client/src/components/production-list-columns/production-list-columns.data.js index 7d122200d..fe9d8c7bb 100644 --- a/client/src/components/production-list-columns/production-list-columns.data.js +++ b/client/src/components/production-list-columns/production-list-columns.data.js @@ -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 }) => { ), }, + { + title: i18n.t("timetickets.actions.claimtasks"), + dataIndex: "claimtasks", + key: "claimtasks", + ellipsis: true, + render: (text, record) => ( +
{ + store.dispatch( + setModalContext({ + context: { + actions: {}, + context: { jobid: record.id }, + }, + modal: "timeTicketTask", + }) + ); + }} + > + {i18n.t("timetickets.actions.claimtasks")} +
+ ), + }, { title: i18n.t("jobs.fields.ro_number"), dataIndex: "ro_number", diff --git a/client/src/components/tech-sider/tech-sider.component.jsx b/client/src/components/tech-sider/tech-sider.component.jsx index c6ea4f67f..33eae1e0b 100644 --- a/client/src/components/tech-sider/tech-sider.component.jsx +++ b/client/src/components/tech-sider/tech-sider.component.jsx @@ -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 ( }> {t("menus.tech.joblookup")} - } - > - {t("menus.tech.jobclockin")} - + {Enhanced_Payroll.treatment === "on" ? ( + } + onClick={() => { + setTimeTicketTaskContext({ + actions: {}, + context: { jobid: null }, + }); + }} + > + {t("menus.tech.claimtask")} + + ) : ( + } + > + {t("menus.tech.jobclockin")} + + )} + @@ -116,7 +121,7 @@ export function TimeTicketTaskModalComponent({ {t("timetickets.labels.claimtaskpreview")} -
{t("bodyshop.fields.md_tasks_presets.percent")}
+
@@ -173,6 +178,14 @@ export function TimeTicketTaskModalComponent({ }} )} + {unassignedHours > 0 && ( + + )} diff --git a/client/src/components/time-ticket-task-modal/time-ticket-task-modal.container.jsx b/client/src/components/time-ticket-task-modal/time-ticket-task-modal.container.jsx index 9bb1fb009..a386d200e 100644 --- a/client/src/components/time-ticket-task-modal/time-ticket-task-modal.container.jsx +++ b/client/src/components/time-ticket-task-modal/time-ticket-task-modal.container.jsx @@ -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} /> diff --git a/client/src/components/time-ticket-task-modal/time-ticket-task-modal.styles.scss b/client/src/components/time-ticket-task-modal/time-ticket-task-modal.styles.scss new file mode 100644 index 000000000..91fd3345e --- /dev/null +++ b/client/src/components/time-ticket-task-modal/time-ticket-task-modal.styles.scss @@ -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; + } +} diff --git a/client/src/pages/tech/tech.page.component.jsx b/client/src/pages/tech/tech.page.component.jsx index 50219f72d..25b33dc09 100644 --- a/client/src/pages/tech/tech.page.component.jsx +++ b/client/src/pages/tech/tech.page.component.jsx @@ -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 }) { +
{t("timetickets.fields.employee")}