diff --git a/client/src/components/job-search-select/job-search-select.component.jsx b/client/src/components/job-search-select/job-search-select.component.jsx index 4dd32393d..85c160ad2 100644 --- a/client/src/components/job-search-select/job-search-select.component.jsx +++ b/client/src/components/job-search-select/job-search-select.component.jsx @@ -4,7 +4,14 @@ const { Option } = Select; //To be used as a form element only. -const JobSearchSelect = ({ value, onChange, options, onBlur, disabled }) => { +const JobSearchSelect = ({ + value, + onChange, + options, + onBlur, + disabled, + loading, +}) => { const [option, setOption] = useState(value); useEffect(() => { @@ -22,6 +29,7 @@ const JobSearchSelect = ({ value, onChange, options, onBlur, disabled }) => { style={{ width: 300, }} + loading={loading} onChange={setOption} optionFilterProp="children" onBlur={onBlur} diff --git a/client/src/components/tech-clock-in/tech-clock-in.component.jsx b/client/src/components/tech-clock-in/tech-clock-in.component.jsx new file mode 100644 index 000000000..61c916683 --- /dev/null +++ b/client/src/components/tech-clock-in/tech-clock-in.component.jsx @@ -0,0 +1,41 @@ +import { useQuery } from "@apollo/react-hooks"; +import React from "react"; +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"; +const mapStateToProps = createStructuredSelector({ + bodyshop: selectBodyshop, + + }); + +export function TechClockInComponent({ form, bodyshop }) { + const { t } = useTranslation(); + const { loading, data } = useQuery(ACTIVE_JOBS_FOR_AUTOCOMPLETE, { + variables: { + statuses: bodyshop.md_ro_statuses.open_statuses || ["Open"], + }, + }); + + return ( +
+ + + +
+ ); +} +export default connect(mapStateToProps, null)(TechClockInComponent); 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 new file mode 100644 index 000000000..277986354 --- /dev/null +++ b/client/src/components/tech-clock-in/tech-clock-in.container.jsx @@ -0,0 +1,44 @@ +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-lookup-jobs-drawer/tech-lookup-jobs-drawer.component.jsx b/client/src/components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component.jsx index 989320d19..d4c761808 100644 --- a/client/src/components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component.jsx +++ b/client/src/components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component.jsx @@ -1,6 +1,6 @@ import { PrinterFilled } from "@ant-design/icons"; import { useQuery } from "@apollo/react-hooks"; -import { Button, Col, Drawer, Grid, PageHeader, Row, Tag } from "antd"; +import { Button, Col, Drawer, Grid, PageHeader, Row, Tag, Tabs } from "antd"; import queryString from "query-string"; import React from "react"; import { useTranslation } from "react-i18next"; @@ -12,6 +12,9 @@ import AlertComponent from "../alert/alert.component"; import LoadingSpinner from "../loading-spinner/loading-spinner.component"; import OwnerTagPopoverComponent from "../owner-tag-popover/owner-tag-popover.component"; import VehicleTagPopoverComponent from "../vehicle-tag-popover/vehicle-tag-popover.component"; +import JobLinesContainer from "../job-detail-lines/job-lines.container"; +import JobsDocumentsGalleryContainer from "../jobs-documents-gallery/jobs-documents-gallery.container"; +import JobNotesContainer from "../jobs-notes/jobs-notes.container"; const mapDispatchToProps = (dispatch) => ({ setPrintCenterContext: (context) => @@ -23,7 +26,7 @@ const colBreakPoints = { span: 24, }, sm: { - span: 12, + span: 8, }, }; @@ -115,10 +118,21 @@ export function JobDetailCards({ setPrintCenterContext }) { } > - - - + What would be good to have here? + What would be good to have here? + What would be good to have here? + + + + + + + + + + + ) : null} diff --git a/client/src/graphql/accounting.queries.js b/client/src/graphql/accounting.queries.js index 4202efc27..8e2c6c8ed 100644 --- a/client/src/graphql/accounting.queries.js +++ b/client/src/graphql/accounting.queries.js @@ -52,7 +52,7 @@ export const QUERY_INVOICES_FOR_EXPORT = gql` export const QUERY_PAYMENTS_FOR_EXPORT = gql` query QUERY_PAYMENTS_FOR_EXPORT { payments( - where: { exportedat: { _eq: null } } + where: { exportedat: { _is_null: true } } order_by: { created_at: desc } ) { id diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js index f8ffee563..694109c89 100644 --- a/client/src/graphql/jobs.queries.js +++ b/client/src/graphql/jobs.queries.js @@ -371,6 +371,72 @@ export const QUERY_JOB_CARD_DETAILS = gql` } `; +export const QUERY_TECH_JOB_DETAILS = gql` + query QUERY_TECH_JOB_DETAILS($id: uuid!) { + jobs_by_pk(id: $id) { + ownr_fn + ownr_ln + v_model_yr + v_make_desc + v_model_desc + v_color + plate_no + actual_completion + actual_delivery + actual_in + est_number + id + ins_co_nm + clm_no + status + job_totals + area_of_damage + ro_number + scheduled_completion + scheduled_in + scheduled_delivery + date_invoiced + date_open + date_exported + date_closed + date_scheduled + date_estimated + joblines { + id + unq_seq + line_ind + tax_part + line_desc + prt_dsmk_p + prt_dsmk_m + part_type + oem_partno + db_price + act_price + part_qty + mod_lbr_ty + db_hrs + mod_lb_hrs + lbr_op + lbr_amt + op_code_desc + } + notes { + id + text + critical + private + created_at + } + updated_at + documents(order_by: { created_at: desc }) { + id + key + } + } + } +`; + export const UPDATE_JOB = gql` mutation UPDATE_JOB($jobId: uuid!, $job: jobs_set_input!) { update_jobs(where: { id: { _eq: $jobId } }, _set: $job) { diff --git a/client/src/graphql/timetickets.queries.js b/client/src/graphql/timetickets.queries.js index f4aee3273..58d27bad4 100644 --- a/client/src/graphql/timetickets.queries.js +++ b/client/src/graphql/timetickets.queries.js @@ -46,3 +46,18 @@ export const UPDATE_TIME_TICKET = gql` } } `; + +export const QUERY_ACTIVE_TIME_TICKETS = gql` + query QUERY_ACTIVE_TIME_TICKETS($employeeId: uuid) { + timetickets( + where: { + _and: { clockoff: { _is_null: true }, employeeid: { _eq: $employeeId } } + } + ) { + id + job { + ro_number + } + } + } +`; diff --git a/client/src/pages/tech/tech.page.component.jsx b/client/src/pages/tech/tech.page.component.jsx index 528f435e9..efaed2e77 100644 --- a/client/src/pages/tech/tech.page.component.jsx +++ b/client/src/pages/tech/tech.page.component.jsx @@ -27,6 +27,10 @@ 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 { Content } = Layout; const mapStateToProps = createStructuredSelector({ @@ -74,6 +78,11 @@ export function TechPage({ technician, match }) { exact path={`${match.path}/list`} component={ProductionListPage} + />{" "} +