diff --git a/client/src/components/jobs-detail-labor/jobs-detail-labor.component.jsx b/client/src/components/jobs-detail-labor/jobs-detail-labor.component.jsx
index e7e6aea22..93ded43a6 100644
--- a/client/src/components/jobs-detail-labor/jobs-detail-labor.component.jsx
+++ b/client/src/components/jobs-detail-labor/jobs-detail-labor.component.jsx
@@ -3,19 +3,23 @@ import LaborAllocationsTableComponent from "../labor-allocations-table/labor-all
import TimeTicketEnterButton from "../time-ticket-enter-button/time-ticket-enter-button.component";
import TimeTicketList from "../time-ticket-list/time-ticket-list.component";
import { useTranslation } from "react-i18next";
+
export default function JobsDetailLaborContainer({
jobId,
joblines,
timetickets,
refetch,
loading,
+ techConsole,
}) {
const { t } = useTranslation();
return (
-
- {t("timetickets.actions.enter")}
-
+ {techConsole ? null : (
+
+ {t("timetickets.actions.enter")}
+
+ )}
);
diff --git a/client/src/components/jobs-detail-labor/jobs-detail-labor.container.jsx b/client/src/components/jobs-detail-labor/jobs-detail-labor.container.jsx
index 51f631a26..22c4f16d7 100644
--- a/client/src/components/jobs-detail-labor/jobs-detail-labor.container.jsx
+++ b/client/src/components/jobs-detail-labor/jobs-detail-labor.container.jsx
@@ -4,7 +4,7 @@ import { GET_LINE_TICKET_BY_PK } from "../../graphql/jobs-lines.queries";
import AlertComponent from "../alert/alert.component";
import JobsDetailLaborComponent from "./jobs-detail-labor.component";
-export default function JobsDetailLaborContainer({ jobId }) {
+export default function JobsDetailLaborContainer({ jobId, techConsole }) {
const { loading, error, data, refetch } = useQuery(GET_LINE_TICKET_BY_PK, {
variables: { id: jobId },
skip: !!!jobId,
@@ -19,6 +19,7 @@ export default function JobsDetailLaborContainer({ jobId }) {
timetickets={data ? data.timetickets : []}
joblines={data ? data.joblines : []}
refetch={refetch}
+ techConsole={techConsole}
/>
);
}
diff --git a/client/src/components/tech-clock-in/tech-clock-in.container.jsx b/client/src/components/tech-clock-in/tech-clock-in.container.jsx
deleted file mode 100644
index 277986354..000000000
--- a/client/src/components/tech-clock-in/tech-clock-in.container.jsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import { Form, Button } from "antd";
-import React from "react";
-import { useQuery } from "react-apollo";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { QUERY_ACTIVE_TIME_TICKETS } from "../../graphql/timetickets.queries";
-import { selectTechnician } from "../../redux/tech/tech.selectors";
-import AlertComponent from "../alert/alert.component";
-import LoadingSpinner from "../loading-spinner/loading-spinner.component";
-import TechClockInComponent from "./tech-clock-in.component";
-import { useTranslation } from "react-i18next";
-const mapStateToProps = createStructuredSelector({
- technician: selectTechnician,
-});
-
-export function TechClockInContainer({ technician }) {
- const { loading, error, data } = useQuery(QUERY_ACTIVE_TIME_TICKETS);
- const [form] = Form.useForm();
- const { t } = useTranslation();
- if (loading) return ;
- if (error) return ;
-
- console.log("data", data);
-
- if (data.timetickets.length > 0) {
- return already clock into a job.
;
- }
-
- const handleFinish = (values) => {
- console.log("values", values);
- };
-
- return (
-
-
-
- );
-}
-export default connect(mapStateToProps, null)(TechClockInContainer);
diff --git a/client/src/components/tech-clock-in/tech-clock-in.component.jsx b/client/src/components/tech-job-clock-in-form/tech-job-clock-in-form.component.jsx
similarity index 69%
rename from client/src/components/tech-clock-in/tech-clock-in.component.jsx
rename to client/src/components/tech-job-clock-in-form/tech-job-clock-in-form.component.jsx
index 61c916683..e8a8c0465 100644
--- a/client/src/components/tech-clock-in/tech-clock-in.component.jsx
+++ b/client/src/components/tech-job-clock-in-form/tech-job-clock-in-form.component.jsx
@@ -1,17 +1,17 @@
import { useQuery } from "@apollo/react-hooks";
+import { Form } from "antd";
import React from "react";
+import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { ACTIVE_JOBS_FOR_AUTOCOMPLETE } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
-import { selectTechnician } from "../../redux/tech/tech.selectors";
import JobSearchSelect from "../job-search-select/job-search-select.component";
-import { useTranslation } from "react-i18next";
-import { Form } from "antd";
+import JobsDetailLaborContainer from "../jobs-detail-labor/jobs-detail-labor.container";
+
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
-
- });
+ bodyshop: selectBodyshop,
+});
export function TechClockInComponent({ form, bodyshop }) {
const { t } = useTranslation();
@@ -35,6 +35,22 @@ export function TechClockInComponent({ form, bodyshop }) {
>
+
+
+ prevValues.jobid !== curValues.jobid
+ }
+ >
+ {() => {
+ if (!form.getFieldValue("jobid")) return null;
+ return (
+
+ );
+ }}
+
);
}
diff --git a/client/src/components/tech-job-clock-in-form/tech-job-clock-in-form.container.jsx b/client/src/components/tech-job-clock-in-form/tech-job-clock-in-form.container.jsx
new file mode 100644
index 000000000..9d6c823fb
--- /dev/null
+++ b/client/src/components/tech-job-clock-in-form/tech-job-clock-in-form.container.jsx
@@ -0,0 +1,76 @@
+import { Button, Form, notification, Card } from "antd";
+import React from "react";
+import { useMutation } from "react-apollo";
+import { useTranslation } from "react-i18next";
+import { connect } from "react-redux";
+import { createStructuredSelector } from "reselect";
+import { INSERT_NEW_TIME_TICKET } from "../../graphql/timetickets.queries";
+import { selectTechnician } from "../../redux/tech/tech.selectors";
+import { selectBodyshop } from "../../redux/user/user.selectors";
+import TechClockInComponent from "./tech-job-clock-in-form.component";
+
+const mapStateToProps = createStructuredSelector({
+ technician: selectTechnician,
+ bodyshop: selectBodyshop,
+});
+
+export function TechClockInContainer({ technician, bodyshop }) {
+ const [form] = Form.useForm();
+ const [insertTimeTicket] = useMutation(INSERT_NEW_TIME_TICKET, {
+ refetchQueries: ["QUERY_ACTIVE_TIME_TICKETS"],
+ });
+ const { t } = useTranslation();
+
+ const handleFinish = async (values) => {
+ const result = await insertTimeTicket({
+ variables: {
+ timeTicketInput: {
+ employeeid: technician.id,
+ date: new Date(),
+ clockon: new Date(),
+ jobid: values.jobid,
+ cost_center: technician.cost_center,
+ ciecacode: Object.keys(
+ bodyshop.md_responsibility_centers.defaults.costs
+ ).find((key) => {
+ console.log(
+ "key",
+ key,
+ bodyshop.md_responsibility_centers.defaults.costs[key]
+ );
+ return (
+ bodyshop.md_responsibility_centers.defaults.costs[key] ===
+ values.cost_center
+ );
+ }),
+ },
+ },
+ });
+
+ if (!!result.errors) {
+ notification["error"]({
+ message: t("timetickets.errors.clockingin", {
+ message: JSON.stringify(result.errors),
+ }),
+ });
+ } else {
+ notification["success"]({
+ message: t("timetickets.successes.clockedin"),
+ });
+ }
+ };
+
+ return (
+
+
+
+
+
+ );
+}
+export default connect(mapStateToProps, null)(TechClockInContainer);
diff --git a/client/src/components/tech-job-clock-out-button/tech-job-clock-out-button.component.jsx b/client/src/components/tech-job-clock-out-button/tech-job-clock-out-button.component.jsx
new file mode 100644
index 000000000..961cebae3
--- /dev/null
+++ b/client/src/components/tech-job-clock-out-button/tech-job-clock-out-button.component.jsx
@@ -0,0 +1,130 @@
+import { useMutation } from "@apollo/react-hooks";
+import {
+ Button,
+ Card,
+ Form,
+ InputNumber,
+ notification,
+ Popover,
+ Select,
+} from "antd";
+import React, { useState } from "react";
+import { useTranslation } from "react-i18next";
+import { UPDATE_TIME_TICKET } from "../../graphql/timetickets.queries";
+
+import { connect } from "react-redux";
+import { createStructuredSelector } from "reselect";
+import { selectBodyshop } from "../../redux/user/user.selectors";
+import { selectTechnician } from "../../redux/tech/tech.selectors";
+const mapStateToProps = createStructuredSelector({
+ bodyshop: selectBodyshop,
+ technician: selectTechnician,
+});
+
+export function TechClockOffButton({
+ bodyshop,
+ technician,
+ timeTicketId,
+ completedCallback,
+ otherBtnProps,
+}) {
+ const [loading, setLoading] = useState(false);
+ const [updateTimeticket] = useMutation(UPDATE_TIME_TICKET);
+ const [form] = Form.useForm();
+
+ const { t } = useTranslation();
+
+ const handleFinish = async (values) => {
+ setLoading(true);
+ const result = await updateTimeticket({
+ variables: {
+ timeticketId: timeTicketId,
+ timeticket: { clockoff: new Date(), ...values },
+ },
+ });
+
+ if (!!result.errors) {
+ notification["error"]({
+ message: t("timetickets.errors.clockingout", {
+ message: JSON.stringify(result.errors),
+ }),
+ });
+ } else {
+ notification["success"]({
+ message: t("timetickets.successes.clockedout"),
+ });
+ }
+ setLoading(false);
+ if (completedCallback) completedCallback();
+ };
+
+ const overlay = (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+
+ return (
+
+
+
+ );
+}
+export default connect(mapStateToProps, null)(TechClockOffButton);
diff --git a/client/src/components/tech-job-clocked-in-list/tech-job-clocked-in-list.component.jsx b/client/src/components/tech-job-clocked-in-list/tech-job-clocked-in-list.component.jsx
new file mode 100644
index 000000000..bda243583
--- /dev/null
+++ b/client/src/components/tech-job-clocked-in-list/tech-job-clocked-in-list.component.jsx
@@ -0,0 +1,93 @@
+import { Card, List, Typography } from "antd";
+import React from "react";
+import { useQuery } from "react-apollo";
+import { useTranslation } from "react-i18next";
+import { Link } from "react-router-dom";
+import { QUERY_ACTIVE_TIME_TICKETS } from "../../graphql/timetickets.queries";
+import { DateTimeFormatter } from "../../utils/DateFormatter";
+import AlertComponent from "../alert/alert.component";
+import DataLabel from "../data-label/data-label.component";
+import LoadingSpinner from "../loading-spinner/loading-spinner.component";
+import TechClockOffButton from "../tech-job-clock-out-button/tech-job-clock-out-button.component";
+import { selectTechnician } from "../../redux/tech/tech.selectors";
+
+import { connect } from "react-redux";
+import { createStructuredSelector } from "reselect";
+const mapStateToProps = createStructuredSelector({
+ technician: selectTechnician,
+});
+const mapDispatchToProps = (dispatch) => ({
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
+});
+
+export function TechClockedInList({ technician }) {
+ const { loading, error, data, refetch } = useQuery(
+ QUERY_ACTIVE_TIME_TICKETS,
+ {
+ variables: {
+ employeeId: technician.id,
+ },
+ }
+ );
+
+ const { t } = useTranslation();
+
+ if (loading) return ;
+ if (error) return ;
+
+ return (
+
+ {data.timetickets.length > 0 ? (
+
+
+ {t("timetickets.labels.alreadyclockedon")}
+
+
(
+
+
+ {`${ticket.job.ro_number || ticket.job.est_number} ${
+ ticket.job.ownr_fn || ""
+ } ${ticket.job.ownr_ln || ""} ${
+ ticket.job.ownr_co_nm || ""
+ }`}
+
+ }
+ actions={[
+ ,
+ ]}
+ >
+
+ {`
+ ${ticket.job.v_model_yr || ""} ${
+ ticket.job.v_make_desc || ""
+ } ${ticket.job.v_model_desc || ""}`}
+
+
+ {ticket.clockon}
+
+
+
+ )}
+ >
+
+ ) : null}
+
+ );
+}
+export default connect(mapStateToProps, mapDispatchToProps)(TechClockedInList);
diff --git a/client/src/components/tech-sider/tech-sider.component.jsx b/client/src/components/tech-sider/tech-sider.component.jsx
index 3839fe849..9c118914a 100644
--- a/client/src/components/tech-sider/tech-sider.component.jsx
+++ b/client/src/components/tech-sider/tech-sider.component.jsx
@@ -43,7 +43,7 @@ export function TechSider({ technician, techLogout }) {
disabled={!!!technician}
icon={}
>
- {t("menus.tech.clockin")}
+ {t("menus.tech.jobclockin")}
(
-
- {t("general.actions.edit")}
-
- ),
+ render: (text, record) => {
+ if (techConsole) return null;
+ return (
+
+ {t("general.actions.edit")}
+
+ );
+ },
},
];
diff --git a/client/src/graphql/timetickets.queries.js b/client/src/graphql/timetickets.queries.js
index 58d27bad4..c39b509d4 100644
--- a/client/src/graphql/timetickets.queries.js
+++ b/client/src/graphql/timetickets.queries.js
@@ -26,6 +26,13 @@ export const INSERT_NEW_TIME_TICKET = gql`
insert_timetickets(objects: $timeTicketInput) {
returning {
id
+ clockon
+ clockoff
+ employeeid
+ productivehrs
+ actualhrs
+ ciecacode
+ date
}
}
}
@@ -42,6 +49,16 @@ export const UPDATE_TIME_TICKET = gql`
) {
returning {
id
+ clockon
+ clockoff
+ employeeid
+ productivehrs
+ actualhrs
+ ciecacode
+ created_at
+ updated_at
+ jobid
+ date
}
}
}
@@ -51,11 +68,24 @@ export const QUERY_ACTIVE_TIME_TICKETS = gql`
query QUERY_ACTIVE_TIME_TICKETS($employeeId: uuid) {
timetickets(
where: {
- _and: { clockoff: { _is_null: true }, employeeid: { _eq: $employeeId } }
+ _and: {
+ clockoff: { _is_null: true }
+ employeeid: { _eq: $employeeId }
+ clockon: { _is_null: false }
+ }
}
) {
id
+ clockon
job {
+ id
+ est_number
+ ownr_fn
+ ownr_ln
+ ownr_co_nm
+ v_model_desc
+ v_make_desc
+ v_model_yr
ro_number
}
}
diff --git a/client/src/pages/tech-job-clock/tech-job-clock.component.jsx b/client/src/pages/tech-job-clock/tech-job-clock.component.jsx
new file mode 100644
index 000000000..db792b98a
--- /dev/null
+++ b/client/src/pages/tech-job-clock/tech-job-clock.component.jsx
@@ -0,0 +1,12 @@
+import React from "react";
+import TechClockInFormContainer from "../../components/tech-job-clock-in-form/tech-job-clock-in-form.container";
+import TechClockedInList from "../../components/tech-job-clocked-in-list/tech-job-clocked-in-list.component";
+
+export default function TechClockComponent() {
+ return (
+
+
+
+
+ );
+}
diff --git a/client/src/pages/tech/tech.page.component.jsx b/client/src/pages/tech/tech.page.component.jsx
index efaed2e77..5af9d75e5 100644
--- a/client/src/pages/tech/tech.page.component.jsx
+++ b/client/src/pages/tech/tech.page.component.jsx
@@ -27,8 +27,8 @@ const ProductionListPage = lazy(() =>
const ProductionBoardPage = lazy(() =>
import("../production-board/production-board.container")
);
-const TechClockIn = lazy(() =>
- import("../../components/tech-clock-in/tech-clock-in.container")
+const TechJobClockIn = lazy(() =>
+ import("../tech-job-clock/tech-job-clock.component")
);
const { Content } = Layout;
@@ -81,8 +81,8 @@ export function TechPage({ technician, match }) {
/>{" "}
{
+ res.status(200).send(new Date());
+};