Framework for entering time tickets BOD-183 BOD-185
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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 (
|
||||
<div>
|
||||
<Form.Item
|
||||
name="jobid"
|
||||
label={t("jobs.fields.ro_number")}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<JobSearchSelect loading={loading} options={data ? data.jobs : []} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default connect(mapStateToProps, null)(TechClockInComponent);
|
||||
@@ -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 <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
console.log("data", data);
|
||||
|
||||
if (data.timetickets.length > 0) {
|
||||
return <div>already clock into a job.</div>;
|
||||
}
|
||||
|
||||
const handleFinish = (values) => {
|
||||
console.log("values", values);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Form form={form} layout="vertical" onFinish={handleFinish}>
|
||||
<TechClockInComponent form={form} />
|
||||
<Button type="primary" htmlType="submit">
|
||||
{t("timetickets.actions.clockon")}
|
||||
</Button>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default connect(mapStateToProps, null)(TechClockInContainer);
|
||||
@@ -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 }) {
|
||||
}
|
||||
>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col {...colBreakPoints}></Col>
|
||||
<Col {...colBreakPoints}></Col>
|
||||
<Col {...colBreakPoints}></Col>
|
||||
<Col {...colBreakPoints}> What would be good to have here?</Col>
|
||||
<Col {...colBreakPoints}> What would be good to have here?</Col>
|
||||
<Col {...colBreakPoints}> What would be good to have here?</Col>
|
||||
</Row>
|
||||
<Tabs size="large">
|
||||
<Tabs.TabPane key="lines" tab={t("jobs.labels.lines")}>
|
||||
<JobLinesContainer jobId={searchParams.selected} />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane key="documents" tab={t("jobs.labels.documents")}>
|
||||
<JobsDocumentsGalleryContainer jobId={searchParams.selected} />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane key="notes" tab={t("jobs.labels.notes")}>
|
||||
<JobNotesContainer jobId={searchParams.selected} />
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
</PageHeader>
|
||||
) : null}
|
||||
</Drawer>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -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}
|
||||
/>{" "}
|
||||
<Route
|
||||
exact
|
||||
path={`${match.path}/clockin`}
|
||||
component={TechClockIn}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import TechActionTypes from "./tech.types";
|
||||
const INITIAL_STATE = {
|
||||
technician: null,
|
||||
//technician: null,
|
||||
technician: {
|
||||
employee_number: "101",
|
||||
first_name: "***HARDCODED",
|
||||
last_name: "IN REDUCER***",
|
||||
},
|
||||
loginLoading: false,
|
||||
loginError: null,
|
||||
};
|
||||
|
||||
@@ -22,10 +22,12 @@ import {
|
||||
} from "./user.actions";
|
||||
import UserActionTypes from "./user.types";
|
||||
|
||||
export function* onEmailSignInStart() {
|
||||
yield takeLatest(UserActionTypes.EMAIL_SIGN_IN_START, signInWithEmail);
|
||||
}
|
||||
export function* signInWithEmail({ payload: { email, password } }) {
|
||||
try {
|
||||
const { user } = yield auth.signInWithEmailAndPassword(email, password);
|
||||
LogRocket.identify(user.email);
|
||||
|
||||
yield put(
|
||||
signInSuccess({
|
||||
@@ -40,9 +42,9 @@ export function* signInWithEmail({ payload: { email, password } }) {
|
||||
yield put(signInFailure(error));
|
||||
}
|
||||
}
|
||||
//This is the listener fo rthe call, and when it finds it, it triggers somethign else.
|
||||
export function* onEmailSignInStart() {
|
||||
yield takeLatest(UserActionTypes.EMAIL_SIGN_IN_START, signInWithEmail);
|
||||
|
||||
export function* onCheckUserSession() {
|
||||
yield takeLatest(UserActionTypes.CHECK_USER_SESSION, isUserAuthenticated);
|
||||
}
|
||||
export function* isUserAuthenticated() {
|
||||
try {
|
||||
@@ -66,8 +68,9 @@ export function* isUserAuthenticated() {
|
||||
yield put(signInFailure(error));
|
||||
}
|
||||
}
|
||||
export function* onCheckUserSession() {
|
||||
yield takeLatest(UserActionTypes.CHECK_USER_SESSION, isUserAuthenticated);
|
||||
|
||||
export function* onSignOutStart() {
|
||||
yield takeLatest(UserActionTypes.SIGN_OUT_START, signOutStart);
|
||||
}
|
||||
export function* signOutStart() {
|
||||
try {
|
||||
@@ -78,9 +81,7 @@ export function* signOutStart() {
|
||||
yield put(signOutFailure(error.message));
|
||||
}
|
||||
}
|
||||
export function* onSignOutStart() {
|
||||
yield takeLatest(UserActionTypes.SIGN_OUT_START, signOutStart);
|
||||
}
|
||||
|
||||
export function* onUpdateUserDetails() {
|
||||
yield takeLatest(UserActionTypes.UPDATE_USER_DETAILS, updateUserDetails);
|
||||
}
|
||||
@@ -140,7 +141,7 @@ export function* checkInstanceIdSaga({ payload: uid }) {
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
//TODO error handling
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function* onSignInSuccess() {
|
||||
@@ -148,6 +149,7 @@ export function* onSignInSuccess() {
|
||||
}
|
||||
|
||||
export function* signInSuccessSaga({ payload }) {
|
||||
LogRocket.identify(user.email);
|
||||
yield put(setInstanceId(payload.uid));
|
||||
}
|
||||
|
||||
|
||||
@@ -181,6 +181,8 @@ exports.QUERY_EMPLOYEE_PIN = `query QUERY_EMPLOYEE_PIN($shopId: uuid!, $employee
|
||||
last_name
|
||||
first_name
|
||||
employee_number
|
||||
id
|
||||
cost_center
|
||||
pin
|
||||
}
|
||||
}`;
|
||||
|
||||
Reference in New Issue
Block a user