diff --git a/components/job-list-item/job-list-item.component.jsx b/components/job-list-item/job-list-item.component.jsx index cb3b4e5..9d823b3 100644 --- a/components/job-list-item/job-list-item.component.jsx +++ b/components/job-list-item/job-list-item.component.jsx @@ -6,15 +6,16 @@ import { Button, List, Title } from "react-native-paper"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { logImEXEvent } from "../../firebase/firebase.analytics"; -import { setCameraJob, setCameraJobId } from "../../redux/app/app.actions"; +import { setCameraJob, setCameraJobId, setTmTicketJobId } from "../../redux/app/app.actions"; const mapStateToProps = createStructuredSelector({}); const mapDispatchToProps = (dispatch) => ({ setCameraJobId: (id) => dispatch(setCameraJobId(id)), setCameraJob: (job) => dispatch(setCameraJob(job)), + setTmTicketJobId:(id) => dispatch(setTmTicketJobId(id)), }); -export function JobListItem({ setCameraJob, setCameraJobId, item }) { +export function JobListItem({ setCameraJob, setCameraJobId,setTmTicketJobId, item }) { const { t } = useTranslation(); const navigation = useNavigation(); // const _swipeableRow = useRef(null); @@ -71,6 +72,7 @@ export function JobListItem({ setCameraJob, setCameraJobId, item }) { onPress={() => { logImEXEvent("imexmobile_setcamerajobid_row"); setCameraJobId(item.id); + setTmTicketJobId(item.id); setCameraJob(item); navigation.navigate("MediaBrowserTab"); }} diff --git a/components/labor-allocations-table/labor-allocations-table-container.component.jsx b/components/labor-allocations-table/labor-allocations-table-container.component.jsx new file mode 100644 index 0000000..481caef --- /dev/null +++ b/components/labor-allocations-table/labor-allocations-table-container.component.jsx @@ -0,0 +1,43 @@ +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"; +import { GET_LINE_TICKET_BY_PK } from "../../graphql/jobs.queries"; +import ErrorDisplay from "../error-display/error-display.component"; +import { useQuery } from "@apollo/client"; +import { connect } from "react-redux"; + +export function LaborAllocationsTableContainer({ jobId }) { + console.log("LaborAllocationsTableContainer, jobId", jobId); + + const { t } = useTranslation(); + + const { loading, error, data, refetch } = useQuery(GET_LINE_TICKET_BY_PK, { + variables: { id: jobId }, + skip: !!!jobId, + fetchPolicy: "network-only", + nextFetchPolicy: "network-only", + }); + + console.log("LaborAllocationsTableContainer, data", data); + if (error) return ; + + return ( + + {data ? ( + + ) : null} + + + ); +} + +const localStyles = StyleSheet.create({}); +export default connect(null, null)(LaborAllocationsTableContainer); diff --git a/components/labor-allocations-table/labor-allocations-table.component.jsx b/components/labor-allocations-table/labor-allocations-table.component.jsx index df2790b..a058c4a 100644 --- a/components/labor-allocations-table/labor-allocations-table.component.jsx +++ b/components/labor-allocations-table/labor-allocations-table.component.jsx @@ -243,13 +243,13 @@ headerArea:{ margin:1 }, footertext:{ - flex:1, textAlign:'center', textAlignVertical:'center',margin:1 + flex:1, textAlign:'center', textAlignVertical:'center',margin:1,paddingBottom:8 }, headertext:{ - flex:1, textAlign:'center', textAlignVertical:'center',backgroundColor:'blue',margin:1 + flex:1, textAlign:'center', textAlignVertical:'center',margin:1,paddingBottom:8 }, headertextAdjusts:{ - flex:1, textAlign:'center', textAlignVertical:'center',backgroundColor:'green',margin:1 + flex:1, textAlign:'center', textAlignVertical:'center',margin:1,paddingBottom:8 }, diff --git a/components/screen-main/screen-main.component.jsx b/components/screen-main/screen-main.component.jsx index c536eeb..f1cf32e 100644 --- a/components/screen-main/screen-main.component.jsx +++ b/components/screen-main/screen-main.component.jsx @@ -32,12 +32,12 @@ import ScreenSettingsComponent from "../screen-settings/screen-settings.componen import ScreenSignIn from "../screen-sign-in/screen-sign-in.component"; import ScreenSplash from "../screen-splash/screen-splash.component"; -//TODO Inprogress JF add import for screens for time ticket browser here import EmployeeSignIn from "../screen-employee-sign-in/screen-employee-sign-in.component"; import ScreenTimeTicketBrowser from "../screen-time-ticket-browser/screen-time-ticket-browser.component"; import SignOutButton from "../Buttons/employee-sign-out-button.component"; import AddTimeTicketButton from "../Buttons/create-time-ticket-button.component"; import ScreenTimeTicketCreate from "../time-ticket/screen-time-ticket-create.component"; +import ScreenTimeTicketClockoffComponent from "../time-ticket/screen-time-ticket-clockoff.component"; const ActiveJobStack = createNativeStackNavigator(); const MoreStack = createNativeStackNavigator(); @@ -123,7 +123,6 @@ const MoreStackNavigator = () => ( ); -//ADDED JF TimeTicketBrowserStackNavigator for navigating the stack and logout on appState background const TimeTicketBrowserStackNavigator = connect( mapStateToProps2, mapDispatchToProps2 @@ -138,7 +137,6 @@ const TimeTicketBrowserStackNavigator = connect( // if (appState.current.match(/active/) && nextAppState === "inactive") { // console.log("App is about to be inactive"); // } - if ( appState.current.match(/active|inactive/) && nextAppState === "background" @@ -146,12 +144,9 @@ const TimeTicketBrowserStackNavigator = connect( // console.log("App is about to be background"); signOut(); } - // if ( appState.current.match(/inactive/)) { console.log("App has come to the inactive"); } // if (appState.current.match(/background/)) { console.log("App has come to the background");} - appState.current = nextAppState; - // console.log("AppState", appState.current); }); return () => { subscription.remove(); @@ -188,6 +183,13 @@ const TimeTicketBrowserStackNavigator = connect( })} component={ScreenTimeTicketCreate} /> + ({ + title: "Clock Off", + })} + component={ScreenTimeTicketClockoffComponent} + /> ) : ( - Time Ticket List goes here - + createTheTimeTicketOBJTest + */} {/* {signingErrorMsg} */} ({ -// setCameraJobId: (id) => dispatch(setCameraJobId(id)), -// setCameraJob: (job) => dispatch(setCameraJob(job)), -// }); +const mapStateToProps = createStructuredSelector({}); +const mapDispatchToProps = (dispatch) => ({ + // setTimeTicketJobId: (jobId) =>dispatch(setTimeTicketJobId({jobId})), + setTmTicketJobId:(id) => dispatch(setTmTicketJobId(id)), +}); -export function ClockedinListItem({ ticket }) { +export function ClockedinListItem({ setTmTicketJobId, 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, - // }); + const onPress = (ticket, setCameraJobId) => { console.log("ClockedinListItem, onPress called"); + console.log("ClockedinListItem, ticket", ticket); + setTimeTicketJobId(ticket.jobid); + // logImEXEvent("imexmobile_view_job_detail"); + navigation.push("TimeTicketClockOff", { + jobId: ticket.jobid, //item.id, + timeTicketId: ticket.id, + //completedCallback: refetch, + }); + // navigation.push("JobDetail", { + // jobId: item.id, + // timeTicketId: item.ro_number || t("general.labels.na"), + // job: item, + // }); + // () => {navigation.navigate("TimeTicketClockOff");} }; return ( @@ -36,18 +47,20 @@ export function ClockedinListItem({ ticket }) { } ${OwnerNameDisplayFunction(ticket.job)}`} /> - Vehicle : - {`${ticket.job.v_model_yr || ""} ${ - ticket.job.v_make_desc || "" - } ${ticket.job.v_model_desc || ""}`} + + 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} + Cost Center :{" "} + {ticket.cost_center === "timetickets.labels.shift" + ? t(ticket.cost_center) + : ticket.cost_center} @@ -56,8 +69,25 @@ export function ClockedinListItem({ ticket }) { timeTicketId={ticket.id} completedCallback={refetch} /> */} - + // { ); } -export default connect( - mapStateToProps, - mapDispatchToProps -)(EmployeeClockedInList); +export default connect(mapStateToProps,null)(EmployeeClockedInList); diff --git a/components/time-ticket/screen-time-ticket-clockoff.component.jsx b/components/time-ticket/screen-time-ticket-clockoff.component.jsx new file mode 100644 index 0000000..01a99a8 --- /dev/null +++ b/components/time-ticket/screen-time-ticket-clockoff.component.jsx @@ -0,0 +1,218 @@ +import { Formik } from "formik"; +import React, { useState } from "react"; +import { StyleSheet, Text, View, ScrollView } from "react-native"; +import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { Button, TextInput } from "react-native-paper"; +import { CostCenterSelect } from "../Selects/select-cost-center"; +import { + selectCurrentEmployee, + selectRates, +} from "../../redux/employee/employee.selectors"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +import LaborAllocationsTable from "../labor-allocations-table/labor-allocations-table.component"; +import { UPDATE_TIME_TICKET } from "../../graphql/timetickets.queries"; +import { useMutation } from "@apollo/client"; +import { selectCurrentTmTicketJobId } from "../../redux/app/app.selectors"; +import ErrorDisplay from "../error-display/error-display.component"; +// import { selectCurrentTimeTicketJobId } from "../../redux/timetickets/timetickets.selectors"; + +//TODO add props needed for call +const mapStateToProps = createStructuredSelector({ + currentEmployee: selectCurrentEmployee, + currentRatesNCostCenters: selectRates, + currentBodyshop: selectBodyshop, + currentTmTicketJobId: selectCurrentTmTicketJobId, +// currentJobId: selectCurrentTimeTicketJobId +}); +// const mapDispatchToProps = (dispatch) => ({}); + +export function TimeTicketClockOff({ + currentEmployee, + currentRatesNCostCenters, + currentBodyshop, + currentTmTicketJobId, +}) { + console.log("TimeTicketClockOff, currentEmployee :", currentEmployee); + //console.log("TimeTicketClockOff, currentRatesNCostCenters :", currentRatesNCostCenters ); + console.log("TimeTicketClockOff, currentBodyshop :", currentBodyshop); + +console.log("TimeTicketClockOff, currentTmTicketJobId :", currentTmTicketJobId); +// console.log("TimeTicketClockOff, jobId :", jobId); +// console.log("TimeTicketClockOff, timeTicketId :", timeTicketId); + const { t } = useTranslation(); + +// const [isDatePickerVisible, setDatePickerVisibility] = useState(false); +// const [date2, setDate2] = useState(new Date()); + const [loading, setLoading] = useState(false); + + const [currentSCC, setCurrentSCC] = useState(null); + // const [currentSJob, setCurrentSJob] = useState(null); + const [currentSJobId, setCurrentSJobId] = useState(currentTmTicketJobId ? currentTmTicketJobId : null); +// const [updateTimeticket] = useMutation(UPDATE_TIME_TICKET); + // const wrapperSetCurrentSJobState = useCallback( + // (val) => { + // setCurrentSJob(val); + // }, + // [setCurrentSJob] + // ); + + // const showDatePicker = () => { + // setDatePickerVisibility(true); + // }; + // const hideDatePicker = () => { + // setDatePickerVisibility(false); + // }; + // const handleConfirm = (date) => { + // setDate2(date); + // //console.war1n("A date has been picked: ", date); + // hideDatePicker(); + // }; + const formSubmit = (values) => { + console.log("values", values); + //Dialog.alert({ content:
{JSON.stringify(values, null, 2)}
}); + //TODO update with start call for create time ticket + }; + +// const handleFinish = async (values) => { +// //logImEXEvent("tech_clock_out_job"); + +// setLoading(true); +// const result = await updateTimeticket({ +// variables: { +// timeticketId: timeTicketId, +// timeticket: { +// clockoff: (await axios.post("/utils/time")).data, +// ...values, +// rate: currentSCC?.rate, +// // emps && +// // emps.rates.filter((r) => r.cost_center === values.cost_center)[0] +// // ?.rate, +// flat_rate: currentEmployee && currentEmployee?.technician?.flat_rate, +// 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 (!!result.errors) { +// console.log("Error handleFinish clock off"); + +// //if (error) return ; + +// // notification["error"]({ +// // message: t("timetickets.errors.clockingout", { +// // message: JSON.stringify(result.errors), +// // }), +// // }); +// } else { +// console.log("success"); +// // notification["success"]({ +// // message: t("timetickets.successes.clockedout"), +// // }); +// } +// setLoading(false); +// if (completedCallback) completedCallback(); +// }; + + return ( + + + + {({ handleChange, handleBlur, handleSubmit, values }) => ( + + {/* */} + + + + + + )} + + + + + + + ); +} + +export default connect(mapStateToProps, null)(TimeTicketClockOff); + +const localStyles = StyleSheet.create({ + content: { + display: "flex", + flex: 1, + }, + topContainer: {}, + bottomContainer: {}, + input: {}, + dateButton: { + marginVertical: 4, + marginHorizontal: 16, + height: 48, + justifyContent: "center", + alignContent: "center", + borderColor: "blue", + borderWidth: 0.8, + flex: 1, + }, + textForButton: { + flex: 1, + justifyContent: "center", + alignContent: "center", + }, + inputStyle: { + marginVertical: 4, + marginHorizontal: 16, + height: 48, + fontSize: 16, + }, +}); diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index 3d051ac..0a19bff 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -17,6 +17,8 @@ import { useCallback } from "react"; // import LaborAllocationsTable from "../labor-allocations-table/labor-allocations-table.component"; import LaborAllocationsTable from "../labor-allocations-table/labor-allocations-table.component"; +import ErrorDisplay from "../error-display/error-display.component"; + //TODO add props needed for call const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, diff --git a/redux/app/app.actions.js b/redux/app/app.actions.js index 1aeb536..551ad03 100644 --- a/redux/app/app.actions.js +++ b/redux/app/app.actions.js @@ -27,3 +27,8 @@ export const documentUploadFailure = (error) => ({ export const toggleDeleteAfterUpload = () => ({ type: AppActionTypes.TOGGLE_DLETE_AFTER_UPLOAD, }); + +export const setTmTicketJobId = (jobId) => ({ + type: AppActionTypes.SET_TM_TICKET_JOB_ID, + payload: jobId, +}); diff --git a/redux/app/app.reducer.js b/redux/app/app.reducer.js index aa15d0c..02f5dfe 100644 --- a/redux/app/app.reducer.js +++ b/redux/app/app.reducer.js @@ -6,6 +6,7 @@ const INITIAL_STATE = { documentUploadInProgress: null, documentUploadError: null, deleteAfterUpload: false, + tmTicketJobId: null, }; const appReducer = (state = INITIAL_STATE, action) => { @@ -43,6 +44,11 @@ const appReducer = (state = INITIAL_STATE, action) => { ...state, deleteAfterUpload: !state.deleteAfterUpload, }; + case AppActionTypes.SET_TM_TICKET_JOB_ID: + return { + ...state, + tmTicketJobId: action.payload, + }; default: return state; } diff --git a/redux/app/app.selectors.js b/redux/app/app.selectors.js index 4626679..15ec19a 100644 --- a/redux/app/app.selectors.js +++ b/redux/app/app.selectors.js @@ -26,3 +26,8 @@ export const selectDeleteAfterUpload = createSelector( [selectApp], (app) => app.deleteAfterUpload ); + +export const selectCurrentTmTicketJobId = createSelector( + [selectApp], + (app) => app.tmTicketJobId +); diff --git a/redux/app/app.types.js b/redux/app/app.types.js index 029d8e0..d2fd50b 100644 --- a/redux/app/app.types.js +++ b/redux/app/app.types.js @@ -5,5 +5,6 @@ const AppActionTypes = { DOCUMENT_UPLOAD_SUCCESS: "DOCUMENT_UPLOAD_SUCCESS", DOCUMENT_UPLOAD_FAILURE: "DOCUMENT_UPLOAD_FAILURE", TOGGLE_DLETE_AFTER_UPLOAD: "TOGGLE_DLETE_AFTER_UPLOAD", + SET_TM_TICKET_JOB_ID: "SET_TM_TICKET_JOB_ID" }; export default AppActionTypes; diff --git a/redux/root.saga.js b/redux/root.saga.js index 8f41c44..ff89eab 100644 --- a/redux/root.saga.js +++ b/redux/root.saga.js @@ -6,5 +6,5 @@ import { employeeSagas } from "./employee/employee.sagas"; import { timeTicketsSagas } from "./timetickets/timetickets.sagas"; export default function* rootSaga() { - yield all([call(userSagas), call(appSagas), call(photosSagas), call(employeeSagas), call(timeTicketsSagas)]); + yield all([call(userSagas), call(appSagas), call(photosSagas), call(employeeSagas), call(timeTicketsSagas),]); } diff --git a/redux/timetickets/timetickets.actions.js b/redux/timetickets/timetickets.actions.js index 57c1c46..b1bcfd4 100644 --- a/redux/timetickets/timetickets.actions.js +++ b/redux/timetickets/timetickets.actions.js @@ -1,4 +1,5 @@ import TimeTicketsActionTypes from "./timetickets.types"; + export const setTimeTicket = (timeTicket) => ({ type: TimeTicketsActionTypes.SET_TIME_TICKET, payload: timeTicket, diff --git a/redux/timetickets/timetickets.reducer.js b/redux/timetickets/timetickets.reducer.js index d63bf7a..075db46 100644 --- a/redux/timetickets/timetickets.reducer.js +++ b/redux/timetickets/timetickets.reducer.js @@ -1,9 +1,8 @@ import TimeTicketsActionTypes from "./timetickets.types"; const INITIAL_STATE = { - timeTicket: null, - timeTickets: [], - timeTicketJobId: null, + ttjobid:null, + timeticketjobid: null, timeTicketJob: null, uploadTimeTicketInProgress: false, uploadTimeTicketError: null, @@ -14,22 +13,19 @@ const timeTicketsReducer = (state = INITIAL_STATE, action) => { case TimeTicketsActionTypes.SET_TIME_TICKET: return { ...state, - timeTicket: action.payload, + timeTicket: action.payload }; case TimeTicketsActionTypes.SET_TIME_TICKET_JOB_ID: - return { - ...state, - timeTicketJobId: action.payload, - }; + return { ...state,timeticketjobid: action.payload }; case TimeTicketsActionTypes.SET_TIME_TICKET_JOB: return { ...state, - timeTicketJob: action.payload, + timeTicketJob: action.payload }; case TimeTicketsActionTypes.TIME_TICKET_CREATE_START: return { ...state, - uploadTimeTicketInProgress: true, + uploadTimeTicketInProgress: true }; case TimeTicketsActionTypes.TIME_TICKET_CREATE_SUCCESS: return { diff --git a/redux/timetickets/timetickets.sagas.js b/redux/timetickets/timetickets.sagas.js index 602297e..6ea8c7f 100644 --- a/redux/timetickets/timetickets.sagas.js +++ b/redux/timetickets/timetickets.sagas.js @@ -29,39 +29,39 @@ export function* insertNewTimeTicket({ payload: { timeTicketInput } }) { // pin: pin, // }); // const { valid, data, error } = response.data; - const result = yield client.mutate({ - mutation: INSERT_NEW_TIME_TICKET, - variables: { - timeTicketInput: [ - // { - // bodyshopid: bodyshop.id, - // employeeid: technician.id, - // date: moment(theTime).format("YYYY-MM-DD"), - // clockon: moment(theTime), - // jobid: values.jobid, - // cost_center: values.cost_center, - // ciecacode: - // bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber - // ? values.cost_center - // : Object.keys( - // bodyshop.md_responsibility_centers.defaults.costs - // ).find((key) => { - // return ( - // bodyshop.md_responsibility_centers.defaults.costs[key] === - // values.cost_center - // ); - // }), - // }, - ], - }, - }); - console.log(result); - const { valid, data, error } = result.data; - if (valid) { - yield put(timeTicketCreateSuccess(data)); - } else { - yield put(timeTicketCreateFailure(error)); - } + // const result = yield client.mutate({ + // mutation: INSERT_NEW_TIME_TICKET, + // variables: { + // timeTicketInput: [ + // // { + // // bodyshopid: bodyshop.id, + // // employeeid: technician.id, + // // date: moment(theTime).format("YYYY-MM-DD"), + // // clockon: moment(theTime), + // // jobid: values.jobid, + // // cost_center: values.cost_center, + // // ciecacode: + // // bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber + // // ? values.cost_center + // // : Object.keys( + // // bodyshop.md_responsibility_centers.defaults.costs + // // ).find((key) => { + // // return ( + // // bodyshop.md_responsibility_centers.defaults.costs[key] === + // // values.cost_center + // // ); + // // }), + // // }, + // ], + // }, + // }); + // console.log(result); + // const { valid, data, error } = result.data; + // if (valid) { + // yield put(timeTicketCreateSuccess(data)); + // } else { + // yield put(timeTicketCreateFailure(error)); + // } } catch (error) { yield put(timeTicketCreateFailure(error)); } diff --git a/redux/timetickets/timetickets.selectors.js b/redux/timetickets/timetickets.selectors.js index a493260..335e21e 100644 --- a/redux/timetickets/timetickets.selectors.js +++ b/redux/timetickets/timetickets.selectors.js @@ -14,3 +14,4 @@ export const selectCurrentTimeTicket = createSelector( [selectTimeTicketsState], (timeTickets) => timeTickets.timeTicket ); +