From 66fa8196afd8c8fe5709cafb69f72bea36759888 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Sat, 13 May 2023 13:56:44 -0400 Subject: [PATCH] fixbugwithselectordropdownaddedclockedinlist --- components/Selects/select-cost-center.jsx | 4 +- components/Selects/select-job-id.jsx | 135 +++++++++++------- .../labor-allocations-table.component.jsx | 73 ++++++++++ .../screen-time-ticket-browser.component.jsx | 83 ++++++----- .../clockedin-list-item.component.jsx | 94 ++++++++++++ .../employee-clockedin-list.component.jsx | 111 ++++++++++++++ .../screen-time-ticket-create.component.jsx | 50 ++++--- graphql/timetickets.queries.js | 33 +++++ redux/employee/employee.selectors.js | 4 + util/DateFormater.jsx | 24 ++++ 10 files changed, 505 insertions(+), 106 deletions(-) create mode 100644 components/labor-allocations-table/labor-allocations-table.component.jsx create mode 100644 components/time-ticket-items/clockedin-list-item.component.jsx create mode 100644 components/time-ticket-lists/employee-clockedin-list.component.jsx create mode 100644 util/DateFormater.jsx diff --git a/components/Selects/select-cost-center.jsx b/components/Selects/select-cost-center.jsx index 1925d85..81abd44 100644 --- a/components/Selects/select-cost-center.jsx +++ b/components/Selects/select-cost-center.jsx @@ -53,16 +53,16 @@ export function CostCenterSelect(props) { selectedTextStyle={styles.selectedTextStyle} inputSearchStyle={styles.inputSearchStyle} iconStyle={styles.iconStyle} - data={costCenters} search maxHeight={300} labelField="label" valueField="value" placeholder={!isFocus ? "Select Cost Center" : "..."} searchPlaceholder="Search..." - value={props.currentValue?.value} onFocus={() => setIsFocus(true)} onBlur={() => setIsFocus(false)} + data={costCenters} + value={props.currentValue?.value} onChange={(item) => { props.onValueSelected(item); //setValue(item.value); diff --git a/components/Selects/select-job-id.jsx b/components/Selects/select-job-id.jsx index 49f54cd..404888e 100644 --- a/components/Selects/select-job-id.jsx +++ b/components/Selects/select-job-id.jsx @@ -1,5 +1,5 @@ import { useLazyQuery } from "@apollo/client"; -import React, { forwardRef, useState, useEffect } from "react"; +import React, { useState, useEffect } from "react"; import { useTranslation } from "react-i18next"; import _ from "lodash"; @@ -12,17 +12,24 @@ import { Dropdown } from "react-native-element-dropdown"; import { connect } from "react-redux"; import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component"; -///This Component is for testing select. This is not for prod. Justin - export function JobIdSearchSelect( - convertedOnly = false, - notInvoiced = false, - notExported = true, - clm_no = false, - onValueSelected, - currentValue, - ...restProps + props + // //currentValue, + // ...restProps ) { +// console.log("JobIdSearchSelectprops:", props); + const notExported = + props.notExported !== undefined ? props.notExported : true; + const notInvoiced = + props.notInvoiced !== undefined ? props.notInvoiced : false; + const convertedOnly = + props.convertedOnly !== undefined ? props.convertedOnly : false; + const clm_no = props.clm_no !== undefined ? props.clm_no : false; + +// console.log("notExported:", notExported); +// console.log("notInvoiced:", notInvoiced); +// console.log("convertedOnly:", convertedOnly); +// console.log("clm_no:", clm_no); const { t } = useTranslation(); const [theOptions, setTheOptions] = useState([]); @@ -33,19 +40,18 @@ export function JobIdSearchSelect( const [callIdSearch, { loading: idLoading, error: idError, data: idData }] = useLazyQuery(SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE); - const [callSearch, { loading, error, data }] = useLazyQuery( SEARCH_JOBS_FOR_AUTOCOMPLETE, {} ); const executeSearch = (v) => { - console.log("executeSearchWithV:", v); + // console.log("executeSearchWithV:", v); if (v && v !== "") callSearch(v); }; const debouncedExecuteSearch = _.debounce(executeSearch, 500); const handleSearch = (value) => { - console.log("handleSearchWithValue:", value); + // console.log("handleSearchWithValue:", value); debouncedExecuteSearch({ variables: { search: value, @@ -60,52 +66,59 @@ export function JobIdSearchSelect( }); }; - useEffect(() => { - console.log("useEfectDependentOn: restProps.value, callIdSearch", restProps); - if (restProps.value) { - console.log("restPropsValue:", restProps.value); - callIdSearch({ variables: { id: restProps.value } }); - } - }, [restProps.value, callIdSearch]); + // useEffect(() => { + // console.log("useEfectDependentOn: restProps.value, callIdSearch", restProps); + // if (restProps.value) { + // console.log("restPropsValue:", restProps.value); + // callIdSearch({ variables: { id: restProps.value } }); + // } + // }, [restProps.value, callIdSearch]); useEffect(() => { - console.log("useEfectDependentOn: [data, idData]"); - - console.log("idDataValue:", (idData && idData.jobs_by_pk ? [idData.jobs_by_pk] : [])); - console.log("dataValue:", (data && data.search_jobs ? data.search_jobs : [])); - setTheOptions( - _.uniqBy( - [ - ...(idData && idData.jobs_by_pk ? [idData.jobs_by_pk] : []), - ...(data && data.search_jobs ? data.search_jobs : []), - ], - "id" - ) - ); + // console.log("useEfectDependentOn: [data, idData]"); + + // console.log( "idDataValue:", idData && idData.jobs_by_pk ? [idData.jobs_by_pk] : []); + // console.log("dataValue:", data && data.search_jobs ? data.search_jobs : []); + + if (data) { + setTheOptions( + _.uniqBy( + [ + ...(idData && idData.jobs_by_pk ? [idData.jobs_by_pk] : []), + ...(data && data.search_jobs ? data.search_jobs : []), + ], + "id" + ) + ); + } }, [data, idData]); useEffect(() => { - console.log("useEfectDependentOn: [theOptions]"); + // console.log("useEfectDependentOn: [theOptions]"); var count = Object.keys(theOptions).length; + console.log("useEfectDependentOn: [theOptions] count:", count); let selectDataArray = []; for (let i = 0; i < count; i++) { - // let o = theOptions[i]; selectDataArray.push({ value: theOptions[i].id, - label: theOptions[i].ro_number, - - // `${clm_no && o.clm_no ? `${o.clm_no} | ` : ""}${ - // o.ro_number || t("general.labels.na") - // } | ${OwnerNameDisplayFunction(o)} | ${o.v_model_yr || ""} ${o.v_make_desc || ""} ${ - // o.v_model_desc || "" - // }`, - + label: `${clm_no && theOptions[i].clm_no ? `${theOptions[i].clm_no} | ` : ""}${ + theOptions[i].ro_number || t("general.labels.na") + } | ${OwnerNameDisplayFunction(theOptions[i])} | ${theOptions[i].v_model_yr || ""} ${theOptions[i].v_make_desc || ""} ${ + theOptions[i].v_model_desc || "" + }`, }); } setSelectorData(selectDataArray); }, [theOptions]); - + // useEffect(() => { + // console.log("useEffectonselectedvaluechange:", selectedvalue.value); + // if (typeof onJobSelected !== "undefined") { + // console.log("onJobSelected:", selectedvalue.value); + // onJobSelected(selectedvalue.value); + // } + // }, [selectedvalue]); + return ( setIsFocus(true)} onBlur={() => setIsFocus(false)} - onChange={(item) => { - console.log("onChangefired!!!!"); - console.log("itemSelected", item); - setSelectedValue(item.value); - // onValueSelected(item); - //console.log(item); + data={selectorData} + value={selectedvalue} //{selectedvalue} + onChange={(item) => props.onJobSelected(item)}//TODO: add setIsFocus(false); to this + // { + // console.log("onValueSelected!!!!"); + // // (item) => {onJobSelected(item.value)}; + // console.log("onChangefired!!!!"); + // console.log("itemSelected", item); + // onJobSelected(item.value); + // setSelectedValue(item.value); + + // console.log("onValueSelected",onValueSelected); + // if (onValueSelected){ + // console.log("onValueSelected!!!!"); + // } + + //console.log(item); // setSelectedValue(item.value); // if (onValueSelected) onValueSelected(item.value); - setIsFocus(false); - }} + + // setIsFocus(false); + // }} onChangeText={(search) => { + if (search && search !== "") { console.log("onChangeTextFired!!!!"); - handleSearch(search); + handleSearch(search); + } }} /> {/* {theOptions ? console.log(theOptions): null} */} diff --git a/components/labor-allocations-table/labor-allocations-table.component.jsx b/components/labor-allocations-table/labor-allocations-table.component.jsx new file mode 100644 index 0000000..b7ec0c5 --- /dev/null +++ b/components/labor-allocations-table/labor-allocations-table.component.jsx @@ -0,0 +1,73 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { FlatList, RefreshControl, StyleSheet, Text, View } from "react-native"; +import { Card, DataTable } from "react-native-paper"; + +export default function LaborAllocationsTable({ job, loading, refetch }) { + const { t } = useTranslation(); + + if (!job) { + + Job is not defined. + ; + } + const onRefresh = async () => { + return refetch(); + }; + + return ( + + + + + {t("jobdetail.labels.lines_desc")} + + + {t("jobdetail.labels.lines_lbr_ty")} + + + {t("jobdetail.labels.lines_lb_hrs")} + + + {t("jobdetail.labels.lines_part_type")} + + + {t("jobdetail.labels.lines_qty")} + + + + + + } + keyExtractor={(item) => item.id} + renderItem={(object) => ( + + + {object.item.line_desc} + + + {object.item.mod_lbr_ty && + t(`jobdetail.lbr_types.${object.item.mod_lbr_ty}`)} + + + {object.item.mod_lb_hrs} + + + {object.item.part_type && + t(`jobdetail.part_types.${object.item.part_type}`)} + + + {object.item.part_qty} + + + )} + /> + + ); + } + + const localStyles = StyleSheet.create({}); + \ No newline at end of file diff --git a/components/screen-time-ticket-browser/screen-time-ticket-browser.component.jsx b/components/screen-time-ticket-browser/screen-time-ticket-browser.component.jsx index 66e232b..abd5ac3 100644 --- a/components/screen-time-ticket-browser/screen-time-ticket-browser.component.jsx +++ b/components/screen-time-ticket-browser/screen-time-ticket-browser.component.jsx @@ -1,6 +1,6 @@ import React, { useCallback, useEffect, useState } from "react"; import { View, Text } from "react-native"; - +import axios from "axios"; import { connect } from "react-redux"; import { employeeGetRatesStart } from "../../redux/employee/employee.actions"; import { createStructuredSelector } from "reselect"; @@ -16,13 +16,14 @@ import { Button } from "react-native-paper"; import { useQuery } from "@apollo/client"; import ErrorDisplay from "../error-display/error-display.component"; import { selectBodyshop } from "../../redux/user/user.selectors"; -import { JobSearchSelect } from "../Selects/select-job-name"; +import { JobIdSearchSelect } from "../Selects/select-job-id"; import { CostCenterSelect } from "../Selects/select-cost-center"; import { selectCurrentTimeTicketJob, selectCurrentTimeTicketJobId, } from "../../redux/timetickets/timetickets.selectors"; -import { JobIdSearchSelect } from "../Selects/select-job-id"; +import moment from "moment"; +import { EmployeeClockedInList } from "../time-ticket-lists/employee-clockedin-list.component"; const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, @@ -51,7 +52,7 @@ export function ScreenTimeTicketBrowser({ }) { //const employeeId = currentEmployee.technician.id; const [currentSCC, setCurrentSCC] = useState(null); - const [currentSJob, setCurrentSJob] = useState(null); + // const [currentSJob, setCurrentSJob] = useState(null); const [currentSJobId, setCurrentSJobId] = useState(null); // const { error, data } = useQuery(QUERY_EMPLOYEE_BY_ID, { @@ -60,43 +61,65 @@ export function ScreenTimeTicketBrowser({ // const signingErrorMsg = error ? () : null; // const signingErrorMsg = signingError ? () : null; - const wrapperSetCurrentSJobState = useCallback(val => { - setCurrentSJob(val); - }, [setCurrentSJob]); - + // const wrapperSetCurrentSJobState = useCallback( + // (val) => { + // setCurrentSJobId(val); + // }, + // [setCurrentSJobId] + // ); const getRates = (currentEmployee) => { employeeGetRatesStart(currentEmployee.technician.id); }; - const createTheTimeTicketOBJ = ( + const createTheTimeTicketOBJ = async ( currentEmployee, currentBodyshop, currentSCC, - currentSJob, currentSJobId ) => { - console.log("currentSCC", currentSCC.value); - console.log("currentSJob", currentSJob.value); - console.log("currentSJobId", currentSJobId.value); - console.log("bodyshopid", currentBodyshop.id); - console.log("employeeid", currentEmployee.technician.id); - console.log(currentBodyshop); + const theTime = (await axios.post("/utils/time")).data; + if (currentBodyshop) console.log("bodyshopid", currentBodyshop?.id); + if (currentEmployee) console.log("employeeid", currentEmployee?.technician.id); + if (theTime) console.log("date", moment(theTime).format("YYYY-MM-DD")); + // if (currentSJob) console.log("currentSJob", currentSJob?.value); + if (currentSJobId) console.log("jobid or currentSJobId", currentSJobId?.value); + if (currentSCC) console.log("cost_center or currentSCC", currentSCC?.value); + //if(currentBodyshop)console.log(currentBodyshop); + if (currentBodyshop) + console.log( + "ciecacode", + currentBodyshop?.cdk_dealerid || currentBodyshop?.pbs_serialnumber + ? currentSCC?.value + : Object.keys( + currentBodyshop.md_responsibility_centers.defaults.costs + ).find((key) => { + return ( + currentBodyshop.md_responsibility_centers.defaults.costs[ + key + ] === currentSCC?.value + ); + }) + ); + if (currentEmployee) + console.log("flat_rate", currentEmployee?.technician?.flat_rate); + + if (currentSCC) console.log("rate or currentSCC", currentSCC?.rate); // const temp = { // timeTicketInput: [ // { - // bodyshopid: currentBodyshop?.id, - // employeeid: currentEmployee?.technician?.id, - // date: "2023-05-11", //moment(theTime).format("YYYY-MM-DD"), + //have bodyshopid: currentBodyshop?.id, + //have employeeid: currentEmployee?.technician?.id, + //have date: "2023-05-11", //moment(theTime).format("YYYY-MM-DD"), // //clockon: moment(theTime), // jobid: "temp",//values.jobid, - // cost_center: "temp",//values.cost_center, - // ciecacode: currentBodyshop?.cdk_dealerid || currentBodyshop?.pbs_serialnumber + //have cost_center: "temp",//values.cost_center, + //have ciecacode: currentBodyshop?.cdk_dealerid || currentBodyshop?.pbs_serialnumber // ? values.cost_center // : Object.keys(currentBodyshop.md_responsibility_centers.defaults.costs).find((key) => { // return (currentBodyshop.md_responsibility_centers.defaults.costs[key] === "temp");//values.cost_center); // }), - // flat_rate: currentEmployee.technician.flat_rate, - // rate: 1, + //have flat_rate: currentEmployee.technician.flat_rate, + //have rate: 1, // }, // ], // }; @@ -111,7 +134,7 @@ export function ScreenTimeTicketBrowser({ loading={loaderGettingRates} //onPress={() => getRates(currentEmployee)} onPress={() => - createTheTimeTicketOBJ(currentEmployee, currentBodyshop, currentSCC) + createTheTimeTicketOBJ(currentEmployee, currentBodyshop, currentSCC, currentSJobId) } > text here @@ -119,14 +142,7 @@ export function ScreenTimeTicketBrowser({ {/* {signingErrorMsg} */} - - @@ -139,10 +155,11 @@ export function ScreenTimeTicketBrowser({ mode="outlined" //loading={loaderClockIn} //onPress={() => clockIn()} - > Clock In + + ); } diff --git a/components/time-ticket-items/clockedin-list-item.component.jsx b/components/time-ticket-items/clockedin-list-item.component.jsx new file mode 100644 index 0000000..e5a5cfb --- /dev/null +++ b/components/time-ticket-items/clockedin-list-item.component.jsx @@ -0,0 +1,94 @@ +import { Ionicons } from "@expo/vector-icons"; +import { useNavigation } from "@react-navigation/native"; +import React from "react"; +import { useTranslation } from "react-i18next"; +import { Button, List, Title, Card, Text } from "react-native-paper"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component"; +import { DateTimeFormatter } from "../../util/DateFormater"; + +// const mapStateToProps = createStructuredSelector({}); +// const mapDispatchToProps = (dispatch) => ({ +// setCameraJobId: (id) => dispatch(setCameraJobId(id)), +// setCameraJob: (job) => dispatch(setCameraJob(job)), +// }); + +export function ClockedinListItem({ ticket }) { + const { t } = useTranslation(); + const navigation = useNavigation(); + + const onPress = () => { + // logImEXEvent("imexmobile_view_job_detail"); + // navigation.push("JobDetail", { + // jobId: item.id, + // title: item.ro_number || t("general.labels.na"), + // job: item, + // }); + console.log("ClockedinListItem, onPress called"); + }; + + return ( + + + + Vehicle : + {`${ticket.job.v_model_yr || ""} ${ + ticket.job.v_make_desc || "" + } ${ticket.job.v_model_desc || ""}`} + + + Clocked In : {ticket.clockon} + + + Cost Center : {ticket.cost_center === "timetickets.labels.shift" + ? t(ticket.cost_center) + : ticket.cost_center} + + + + {/* */} + + + + // {item.ro_number || t("general.labels.na")}} + // descriptionNumberOfLines={2} + // description={`${item.ownr_fn || ""} ${item.ownr_ln || ""} ${ + // item.ownr_co_nm || "" + // } - ${item.v_model_yr || ""} ${item.v_make_desc || ""} ${ + // item.v_model_desc || "" + // }`} + // right={({ style }) => ( + // + // )} + // /> + ); +} + +export default connect(null, null)(ClockedinListItem); diff --git a/components/time-ticket-lists/employee-clockedin-list.component.jsx b/components/time-ticket-lists/employee-clockedin-list.component.jsx new file mode 100644 index 0000000..6bfdb3c --- /dev/null +++ b/components/time-ticket-lists/employee-clockedin-list.component.jsx @@ -0,0 +1,111 @@ +import { connect } from "react-redux"; +import { selectCurrentEmployee, selectTechnician } from "../../redux/employee/employee.selectors"; +import { QUERY_ACTIVE_TIME_TICKETS } from "../../graphql/timetickets.queries"; +import { ActivityIndicator,Button, List, Modal, Portal, Searchbar } from "react-native-paper"; +import ErrorDisplay from "../error-display/error-display.component"; +import { View,Text,FlatList, RefreshControl, } from "react-native"; +import { useQuery } from "@apollo/client"; +import { createStructuredSelector } from "reselect"; +import { useTranslation } from "react-i18next"; +import { ClockedinListItem } from "../time-ticket-items/clockedin-list-item.component"; + +const mapStateToProps = createStructuredSelector({ + technician: selectTechnician, + //currentEmployee: selectCurrentEmployee, +}); +const mapDispatchToProps = (dispatch) => ({}); + +export function EmployeeClockedInList({ technician }) { + const { t } = useTranslation(); + + const { loading, error, data, refetch } = useQuery(QUERY_ACTIVE_TIME_TICKETS, { + variables: { + employeeId: technician?.id, + }, + skip: !technician, + fetchPolicy: "network-only", + nextFetchPolicy: "network-only", + } + ); + if (loading) return ; + if (error) return ; + //if (error) return ; +console.log("QUERY_ACTIVE_TIME_TICKETS data",data) + +const onRefresh = async () => { + return refetch(); + }; + return ( + + {data.timetickets.length > 0 ? ( + + You are already clocked in to the following job(s): + } + renderItem={(object) => } /> + + ) : null} + + //
+ // {data.timetickets.length > 0 ? ( + //
+ // + // {t("timetickets.labels.alreadyclockedon")} + // + // ( + // + // + // {`${ + // ticket.job.ro_number || t("general.labels.na") + // } ${OwnerNameDisplayFunction(ticket.job)}`} + // + // } + // actions={[ + // , + // ]} + // > + //
+ // {` + // ${ticket.job.v_model_yr || ""} ${ + // ticket.job.v_make_desc || "" + // } ${ticket.job.v_model_desc || ""}`} + //
+ // + // {ticket.clockon} + // + // + // {ticket.cost_center === "timetickets.labels.shift" + // ? t(ticket.cost_center) + // : ticket.cost_center} + // + //
+ //
+ // )} + // >
+ //
+ // ) : null} + //
+ ); +} + +export default connect( + mapStateToProps, + mapDispatchToProps +)(EmployeeClockedInList); diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index 50e629c..b016ab0 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -1,12 +1,12 @@ import { Formik } from "formik"; import React, { useEffect, useState } from "react"; -import { StyleSheet, Text,View, ScrollView } from "react-native"; +import { StyleSheet, Text, View, ScrollView } from "react-native"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { Button, Dialog, TextInput } from "react-native-paper"; import { CostCenterSelect } from "../Selects/select-cost-center"; -import { JobSearchSelect } from "../Selects/select-job-name"; +import { JobIdSearchSelect } from "../Selects/select-job-id"; import DateTimePickerModal from "react-native-modal-datetime-picker"; import { selectCurrentEmployee, @@ -26,7 +26,7 @@ const mapStateToProps = createStructuredSelector({ export function TimeTicketCreate({ currentEmployee, currentRatesNCostCenters, - currentBodyshop + currentBodyshop, }) { const { t } = useTranslation(); @@ -35,10 +35,14 @@ export function TimeTicketCreate({ const [currentSCC, setCurrentSCC] = useState(null); const [currentSJob, setCurrentSJob] = useState(null); + const [currentSJobId, setCurrentSJobId] = useState(null); - const wrapperSetCurrentSJobState = useCallback(val => { - setCurrentSJob(val); - }, [setCurrentSJob]); + const wrapperSetCurrentSJobState = useCallback( + (val) => { + setCurrentSJob(val); + }, + [setCurrentSJob] + ); const showDatePicker = () => { setDatePickerVisibility(true); @@ -48,7 +52,7 @@ export function TimeTicketCreate({ }; const handleConfirm = (date) => { setDate2(date); - //console.warn("A date has been picked: ", date); + //console.war1n("A date has been picked: ", date); hideDatePicker(); }; const formSubmit = (values) => { @@ -72,14 +76,23 @@ export function TimeTicketCreate({ > {({ handleChange, handleBlur, handleSubmit, values }) => ( - {/* Below will be replaced with a copy of SelectCostCenter but for jobs*/} - - + {/* Below will be replaced with a Date Picker*/} {/* */} - - + + employee.gettingRates ); +export const selectTechnician = createSelector( + [selectEmployee], + (employee) => employee?.currentEmployee?.technician +); diff --git a/util/DateFormater.jsx b/util/DateFormater.jsx new file mode 100644 index 0000000..f5687d9 --- /dev/null +++ b/util/DateFormater.jsx @@ -0,0 +1,24 @@ +import moment from "moment"; +import React from "react"; + +export function DateFormatter(props) { + return props.children + ? moment(props.children).format( + props.includeDay ? "ddd MM/DD/YYYY" : "MM/DD/YYYY" + ) + : null; + } + + export function DateTimeFormatter(props) { + return props.children + ? moment(props.children).format( + props.format ? props.format : "MM/DD/YYYY hh:mm a" + ) + : null; + } + + export function TimeFormatter(props) { + return props.children + ? moment(props.children).format(props.format ? props.format : "hh:mm a") + : null; + } \ No newline at end of file