From 6d4ce20118278274464235a4f2fe9dd8173a5594 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Wed, 5 Apr 2023 17:24:54 -0400 Subject: [PATCH 001/105] expo-updates react-native new 2day old update --- package.json | 4 +- yarn.lock | 122 ++++++++++----------------------------------------- 2 files changed, 26 insertions(+), 100 deletions(-) diff --git a/package.json b/package.json index 6ee0ba9..a6035d5 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "expo-permissions": "^14.1.1", "expo-status-bar": "~1.4.2", "expo-system-ui": "^2.2.1", - "expo-updates": "^0.16.3", + "expo-updates": "^0.16.4", "expo-video-thumbnails": "^7.2.1", "firebase": "^9.8.3", "formik": "^2.2.9", @@ -62,7 +62,7 @@ "react-dom": "^18.2.0", "react-i18next": "^11.17.2", "react-is": ">= 16.8.0", - "react-native": "^0.71.4", + "react-native": "0.71.6", "react-native-dnd-board": "hungga1711/react-native-dnd-board#13/head", "react-native-draggable-flatlist": "^3.1.2", "react-native-gesture-handler": "^2.9.0", diff --git a/yarn.lock b/yarn.lock index a1bd05d..998c833 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2233,7 +2233,7 @@ dependencies: serve-static "^1.13.1" -"@react-native-community/cli-doctor@^10.2.0": +"@react-native-community/cli-doctor@^10.2.2": version "10.2.2" resolved "https://registry.yarnpkg.com/@react-native-community/cli-doctor/-/cli-doctor-10.2.2.tgz#b1893604fa9fc8971064e7c00042350f96868bfe" integrity sha512-49Ep2aQOF0PkbAR/TcyMjOm9XwBa8VQr+/Zzf4SJeYwiYLCT1NZRAVAVjYRXl0xqvq5S5mAGZZShS4AQl4WsZw== @@ -2277,19 +2277,7 @@ glob "^7.1.3" logkitty "^0.7.1" -"@react-native-community/cli-platform-ios@10.2.0": - version "10.2.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-10.2.0.tgz#be21c0e3bbf17358d540cc23e5556bf679f6322e" - integrity sha512-hIPK3iL/mL+0ChXmQ9uqqzNOKA48H+TAzg+hrxQLll/6dNMxDeK9/wZpktcsh8w+CyhqzKqVernGcQs7tPeKGw== - dependencies: - "@react-native-community/cli-tools" "^10.1.1" - chalk "^4.1.2" - execa "^1.0.0" - fast-xml-parser "^4.0.12" - glob "^7.1.3" - ora "^5.4.1" - -"@react-native-community/cli-platform-ios@^10.2.1": +"@react-native-community/cli-platform-ios@10.2.1", "@react-native-community/cli-platform-ios@^10.2.1": version "10.2.1" resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-10.2.1.tgz#2e6bd2cb6d48cbb8720d7b7265bb1bab80745f72" integrity sha512-hz4zu4Y6eyj7D0lnZx8Mf2c2si8y+zh/zUTgCTaPPLzQD8jSZNNBtUUiA1cARm2razpe8marCZ1QbTMAGbf3mg== @@ -2301,7 +2289,7 @@ glob "^7.1.3" ora "^5.4.1" -"@react-native-community/cli-plugin-metro@^10.2.0": +"@react-native-community/cli-plugin-metro@^10.2.2": version "10.2.2" resolved "https://registry.yarnpkg.com/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-10.2.2.tgz#766914e3c8007dfe52b253544c4f6cd8549919ac" integrity sha512-sTGjZlD3OGqbF9v1ajwUIXhGmjw9NyJ/14Lo0sg7xH8Pv4qUd5ZvQ6+DWYrQn3IKFUMfGFWYyL81ovLuPylrpw== @@ -2355,17 +2343,17 @@ dependencies: joi "^17.2.1" -"@react-native-community/cli@10.2.0": - version "10.2.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-10.2.0.tgz#bcb65bb3dcb03b0fc4e49619d51e12d23396b301" - integrity sha512-QH7AFBz5FX2zTZRH/o3XehHrZ0aZZEL5Sh+23nSEFgSj3bLFfvjjZhuoiRSAo7iiBdvAoXrfxQ8TXgg4Xf/7fw== +"@react-native-community/cli@10.2.2": + version "10.2.2" + resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-10.2.2.tgz#3fa438ba7f19f83e07bc337765fc1cabdcf2cac2" + integrity sha512-aZVcVIqj+OG6CrliR/Yn8wHxrvyzbFBY9cj7n0MvRw/P54QUru2nNqUTSSbqv0Qaa297yHJbe6kFDojDMSTM8Q== dependencies: "@react-native-community/cli-clean" "^10.1.1" "@react-native-community/cli-config" "^10.1.1" "@react-native-community/cli-debugger-ui" "^10.0.0" - "@react-native-community/cli-doctor" "^10.2.0" + "@react-native-community/cli-doctor" "^10.2.2" "@react-native-community/cli-hermes" "^10.2.0" - "@react-native-community/cli-plugin-metro" "^10.2.0" + "@react-native-community/cli-plugin-metro" "^10.2.2" "@react-native-community/cli-server-api" "^10.1.1" "@react-native-community/cli-tools" "^10.1.1" "@react-native-community/cli-types" "^10.0.0" @@ -4777,10 +4765,10 @@ expo-updates-interface@~0.9.0: resolved "https://registry.yarnpkg.com/expo-updates-interface/-/expo-updates-interface-0.9.1.tgz#e81308d551ed5a4c35c8770ac61434f6ca749610" integrity sha512-wk88LLhseQ7LJvxdN7BTKiryyqALxnrvr+lyHK3/prg76Yy0EGi2Q/oE/rtFyyZ1JmQDRbO/5pdX0EE6QqVQXQ== -expo-updates@^0.16.3: - version "0.16.3" - resolved "https://registry.yarnpkg.com/expo-updates/-/expo-updates-0.16.3.tgz#190f5896f98db2e130b608d61c8359ee4b2c2125" - integrity sha512-uFr2Fvq7IbKwz9xEqWE9GNEs0sBAd6uiUI9McTCKw4BzKhjylRbPAN3zewc7MGLOvhTwBASva79VLQVgzdoBRw== +expo-updates@^0.16.4: + version "0.16.4" + resolved "https://registry.yarnpkg.com/expo-updates/-/expo-updates-0.16.4.tgz#6d05438cf7304add03645a598211ac4ef3cc4f64" + integrity sha512-hEUotP10sBiYn6dvkYC2rIa+kAmsBuaMp32sIVNAYEwKMQJqEwqNAKTU6CpJ4Aoc//BYL2Hv8qNo/UsT4rATRg== dependencies: "@expo/code-signing-certificates" "0.0.5" "@expo/config" "~8.0.0" @@ -6604,16 +6592,6 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -metro-babel-transformer@0.73.8: - version "0.73.8" - resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.73.8.tgz#521374cb9234ba126f3f8d63588db5901308b4ed" - integrity sha512-GO6H/W2RjZ0/gm1pIvdO9EP34s3XN6kzoeyxqmfqKfYhJmYZf1SzXbyiIHyMbJNwJVrsKuHqu32+GopTlKscWw== - dependencies: - "@babel/core" "^7.20.0" - hermes-parser "0.8.0" - metro-source-map "0.73.8" - nullthrows "^1.1.1" - metro-babel-transformer@0.73.9: version "0.73.9" resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.73.9.tgz#bec8aaaf1bbdc2e469fde586fde455f8b2a83073" @@ -6795,19 +6773,6 @@ metro-react-native-babel-preset@0.73.9: "@babel/template" "^7.0.0" react-refresh "^0.4.0" -metro-react-native-babel-transformer@0.73.8: - version "0.73.8" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.73.8.tgz#cbcd4b243216878431dc4311ce46f02a928e3991" - integrity sha512-oH/LCCJPauteAE28c0KJAiSrkV+1VJbU0PwA9UwaWnle+qevs/clpKQ8LrIr33YbBj4CiI1kFoVRuNRt5h4NFg== - dependencies: - "@babel/core" "^7.20.0" - babel-preset-fbjs "^3.4.0" - hermes-parser "0.8.0" - metro-babel-transformer "0.73.8" - metro-react-native-babel-preset "0.73.8" - metro-source-map "0.73.8" - nullthrows "^1.1.1" - metro-react-native-babel-transformer@0.73.9: version "0.73.9" resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.73.9.tgz#4f4f0cfa5119bab8b53e722fabaf90687d0cbff0" @@ -6828,14 +6793,6 @@ metro-resolver@0.73.9: dependencies: absolute-path "^0.0.0" -metro-runtime@0.73.8: - version "0.73.8" - resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.73.8.tgz#dadae7c154fbbde24390cf7f7e7d934a2768cd18" - integrity sha512-M+Bg9M4EN5AEpJ8NkiUsawD75ifYvYfHi05w6QzHXaqOrsTeaRbbeLuOGCYxU2f/tPg17wQV97/rqUQzs9qEtA== - dependencies: - "@babel/runtime" "^7.0.0" - react-refresh "^0.4.0" - metro-runtime@0.73.9: version "0.73.9" resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.73.9.tgz#0b24c0b066b8629ee855a6e5035b65061fef60d5" @@ -6844,20 +6801,6 @@ metro-runtime@0.73.9: "@babel/runtime" "^7.0.0" react-refresh "^0.4.0" -metro-source-map@0.73.8: - version "0.73.8" - resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.73.8.tgz#5134174e3d43de26ad331b95f637944c6547d441" - integrity sha512-wozFXuBYMAy7b8BCYwC+qoXsvayVJBHWtSTlSLva99t+CoUSG9JO9kg1umzbOz28YYPxKmvb/wbnLMkHdas2cA== - dependencies: - "@babel/traverse" "^7.20.0" - "@babel/types" "^7.20.0" - invariant "^2.2.4" - metro-symbolicate "0.73.8" - nullthrows "^1.1.1" - ob1 "0.73.8" - source-map "^0.5.6" - vlq "^1.0.0" - metro-source-map@0.73.9: version "0.73.9" resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.73.9.tgz#89ca41f6346aeb12f7f23496fa363e520adafebe" @@ -6872,18 +6815,6 @@ metro-source-map@0.73.9: source-map "^0.5.6" vlq "^1.0.0" -metro-symbolicate@0.73.8: - version "0.73.8" - resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.73.8.tgz#96920f607bce484283d822ee5fe18d932f69c03d" - integrity sha512-xkBAcceYYp0GGdCCuMzkCF1ejHsd0lYlbKBkjSRgM0Nlj80VapPaSwumYoAvSaDxcbkvS7/sCjURGp5DsSFgRQ== - dependencies: - invariant "^2.2.4" - metro-source-map "0.73.8" - nullthrows "^1.1.1" - source-map "^0.5.6" - through2 "^2.0.1" - vlq "^1.0.0" - metro-symbolicate@0.73.9: version "0.73.9" resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.73.9.tgz#cb452299a36e5b86b2826e7426d51221635c48bf" @@ -7326,11 +7257,6 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== -ob1@0.73.8: - version "0.73.8" - resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.73.8.tgz#c569f1a15ce2d04da6fd70293ad44b5a93b11978" - integrity sha512-1F7j+jzD+edS6ohQP7Vg5f3yiIk5i3x1uLrNIHOmLHWzWK1t3zrDpjnoXghccdVlsU+UjbyURnDynm4p0GgXeA== - ob1@0.73.9: version "0.73.9" resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.73.9.tgz#d5677a0dd3e2f16ad84231278d79424436c38c59" @@ -8022,7 +7948,7 @@ react-native-gesture-handler@^2.4.0, react-native-gesture-handler@^2.9.0: lodash "^4.17.21" prop-types "^15.7.2" -react-native-gradle-plugin@^0.71.16: +react-native-gradle-plugin@^0.71.17: version "0.71.17" resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.71.17.tgz#cf780a27270f0a32dca8184eff91555d7627dd00" integrity sha512-OXXYgpISEqERwjSlaCiaQY6cTY5CH6j73gdkWpK0hedxtiWMWgH+i5TOi4hIGYitm9kQBeyDu+wim9fA8ROFJA== @@ -8139,15 +8065,15 @@ react-native-web@~0.18.9: postcss-value-parser "^4.2.0" styleq "^0.1.2" -react-native@^0.71.4: - version "0.71.4" - resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.71.4.tgz#f03f600efe68f745d19454ab17f9c1a9ef304790" - integrity sha512-3hSYqvWrOdKhpV3HpEKp1/CkWx8Sr/N/miCrmUIAsVTSJUR7JW0VvIsrV9urDhUj/s6v2WF4n7qIEEJsmTCrPw== +react-native@0.71.6: + version "0.71.6" + resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.71.6.tgz#e8f07baf55abd1015eaa7040ceaa4aa632c2c04f" + integrity sha512-gHrDj7qaAaiE41JwaFCh3AtvOqOLuRgZtHKzNiwxakG/wvPAYmG73ECfWHGxjxIx/QT17Hp37Da3ipCei/CayQ== dependencies: "@jest/create-cache-key-function" "^29.2.1" - "@react-native-community/cli" "10.2.0" + "@react-native-community/cli" "10.2.2" "@react-native-community/cli-platform-android" "10.2.0" - "@react-native-community/cli-platform-ios" "10.2.0" + "@react-native-community/cli-platform-ios" "10.2.1" "@react-native/assets" "1.0.0" "@react-native/normalize-color" "2.1.0" "@react-native/polyfills" "2.0.0" @@ -8160,16 +8086,16 @@ react-native@^0.71.4: jest-environment-node "^29.2.1" jsc-android "^250231.0.0" memoize-one "^5.0.0" - metro-react-native-babel-transformer "0.73.8" - metro-runtime "0.73.8" - metro-source-map "0.73.8" + metro-react-native-babel-transformer "0.73.9" + metro-runtime "0.73.9" + metro-source-map "0.73.9" mkdirp "^0.5.1" nullthrows "^1.1.1" pretty-format "^26.5.2" promise "^8.3.0" react-devtools-core "^4.26.1" react-native-codegen "^0.71.5" - react-native-gradle-plugin "^0.71.16" + react-native-gradle-plugin "^0.71.17" react-refresh "^0.4.0" react-shallow-renderer "^16.15.0" regenerator-runtime "^0.13.2" From bdf90c1f79ac7616a0211e7ad7ffbeaef22cc771 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Wed, 12 Apr 2023 12:04:23 -0400 Subject: [PATCH 002/105] added tech signin screen --- .../screen-tech-sign-in.component.jsx | 80 +++++++++++++++++++ translations/en-US/common.json | 34 ++++++++ translations/es-MX/common.json | 13 +++ translations/fr-CA/common.json | 13 +++ 4 files changed, 140 insertions(+) create mode 100644 components/screen-tech-sign-in/screen-tech-sign-in.component.jsx diff --git a/components/screen-tech-sign-in/screen-tech-sign-in.component.jsx b/components/screen-tech-sign-in/screen-tech-sign-in.component.jsx new file mode 100644 index 0000000..6c257db --- /dev/null +++ b/components/screen-tech-sign-in/screen-tech-sign-in.component.jsx @@ -0,0 +1,80 @@ +import { Formik } from "formik"; +import React from "react"; +import { View, StyleSheet, Text } from "react-native"; +import { Button, TextInput } from "react-native-paper"; +import { useTranslation } from "react-i18next"; + +import { connect } from "react-redux"; + +//TODO JF add props +const mapStateToProps = (state) => ({}); + +//TODO JF add prop functions to call dispatch with actions +const mapDispatchToProps = {}; + +export function TechSignIn({ employeeSignInStart, employeeSigningIn }) { + const { t } = useTranslation(); + +//TODO add call to dispatch action + const formSubmit = (values) => { + const { employeeId, pin } = values; + // techSignInStart(employeeId, pin); + }; + + return ( + + + + {({ handleChange, handleBlur, handleSubmit, values }) => ( + + + + + + )} + + + + ); +} + +const localStyles = StyleSheet.create({ + content: { + display: "flex", + flex: 1, + }, + signInContainer: { + flex: 1, + }, + input: { + margin: 12, + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(TechSignIn); diff --git a/translations/en-US/common.json b/translations/en-US/common.json index 153ab06..0d0fc62 100644 --- a/translations/en-US/common.json +++ b/translations/en-US/common.json @@ -305,6 +305,40 @@ "email": "Email", "password": "Password" } + }, + "techsignin": { + "actions": { + "techsignin": "Sign In" + }, + "errors": { + "employeeidnotfound": "No employee ID found.", + "wrongpin": "The pin you entered is not correct." + }, + "fields": { + "employeeid": "EmployeeID", + "pin": "PIN" + }, + "titles": { + "signin": "Tech Sign In" + } + }, + "timeticketbrowser": { + "actions": { + "refresh": "Refresh", + "upload": "Upload", + "activetickets": "Time Tickets", + "detail": "Time Ticket Details", + "notickets": "There are no active tickets." + }, + "labels": { + "converting": "Converting", + "selectjob": "--- Select a ticket ---", + "selectticketassetselector": "Please select a ticket to update. ", + "uploading": "Uploading" + }, + "titles": { + "timeticketbrowsertab": "Time Tickets" + } } } } diff --git a/translations/es-MX/common.json b/translations/es-MX/common.json index f4a1a3f..f883e6f 100644 --- a/translations/es-MX/common.json +++ b/translations/es-MX/common.json @@ -305,6 +305,19 @@ "email": "Email", "password": "" } + }, + "techsignin": { + "actions": { + "techsignin": "" + }, + "errors": { + "employeeidnotfound": "", + "wrongpin": "" + }, + "fields": { + "employeeid": "", + "pin": "" + } } } } diff --git a/translations/fr-CA/common.json b/translations/fr-CA/common.json index 54de618..30b1675 100644 --- a/translations/fr-CA/common.json +++ b/translations/fr-CA/common.json @@ -305,6 +305,19 @@ "email": "Email", "password": "" } + }, + "techsignin": { + "actions": { + "techsignin": "" + }, + "errors": { + "employeeidnotfound": "", + "wrongpin": "" + }, + "fields": { + "employeeid": "", + "pin": "" + } } } } From d8d8ca0d110db6f391be571a2bf50cbf23bea439 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Wed, 12 Apr 2023 12:05:26 -0400 Subject: [PATCH 003/105] added bottom tab for time tickets --- .../screen-main/screen-main.component.jsx | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/components/screen-main/screen-main.component.jsx b/components/screen-main/screen-main.component.jsx index 46822e3..0f3254b 100644 --- a/components/screen-main/screen-main.component.jsx +++ b/components/screen-main/screen-main.component.jsx @@ -25,12 +25,17 @@ import ScreenMediaBrowser from "../screen-media-browser/screen-media-browser.com import ScreenSettingsComponent from "../screen-settings/screen-settings.component"; 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 TechSignIn from "../screen-tech-sign-in/screen-tech-sign-in.component"; const ActiveJobStack = createNativeStackNavigator(); const MoreStack = createNativeStackNavigator(); const BottomTabs = createBottomTabNavigator(); const MediaBrowserStack = createNativeStackNavigator(); +//ADDED JF TimeTicketBrowserStack for holding screens +const TimeTicketBrowserStack = createNativeStackNavigator(); + const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, currentUser: selectCurrentUser, @@ -104,6 +109,24 @@ const MoreStackNavigator = () => ( ); +//ADDED JF TimeTicketBrowserStackNavigator for navigating the stack +const TimeTicketBrowserStackNavigator = () => ( + + ({ + title: i18n.t("techsignin.titles.signin"), + })} + component={TechSignIn} + /> + {/* */} + +); + const BottomTabsNavigator = () => ( ({ @@ -116,6 +139,8 @@ const BottomTabsNavigator = () => ( iconName = "ios-settings"; } else if (route.name === "MediaBrowserTab") { iconName = "ios-camera"; + } else if (route.name === "TimeTicketBrowserTab") {//ADDED JF check for route.name for TimeTicketBrowserTab. Also icon ios-stopwatch-outline + iconName = "ios-stopwatch-outline"; } else { //iconName = "customerservice"; } @@ -145,8 +170,17 @@ const BottomTabsNavigator = () => ( options={{ title: i18n.t("more.titles.moretab"), headerShown: false }} component={MoreStackNavigator} /> + ); +//ADDED JF BottomTabs.Screen named TimeTicketBrowserTab export function ScreenMainComponent({ checkUserSession, From 35573417c411d95a63a67588883a6d0319c95b5d Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 13 Apr 2023 13:33:12 -0400 Subject: [PATCH 004/105] added employee folder redux --- redux/employee/employee.actions.js | 29 +++++++++++++++++++ redux/employee/employee.reducer.js | 36 ++++++++++++++++++++++++ redux/employee/employee.sagas.js | 42 ++++++++++++++++++++++++++++ redux/employee/employee.selectors.js | 12 ++++++++ redux/employee/employee.types.js | 17 +++++++++++ 5 files changed, 136 insertions(+) create mode 100644 redux/employee/employee.actions.js create mode 100644 redux/employee/employee.reducer.js create mode 100644 redux/employee/employee.sagas.js create mode 100644 redux/employee/employee.selectors.js create mode 100644 redux/employee/employee.types.js diff --git a/redux/employee/employee.actions.js b/redux/employee/employee.actions.js new file mode 100644 index 0000000..c140d23 --- /dev/null +++ b/redux/employee/employee.actions.js @@ -0,0 +1,29 @@ +import EmployeeActionTypes from "./employee.types"; + +export const signInEmployeeStart = (employeeIdAndPin) => ({ + type: EmployeeActionTypes.SIGN_IN_EMPLOYEE_START, + payload: employeeIdAndPin, +}); + +export const signInEmployeeSuccess = (technician) => ({ + type: EmployeeActionTypes.SIGN_IN_EMPLOYEE_SUCCESS, + payload: technician, +}); + +export const signInEmployeeFailure = (error) => ({ + type: EmployeeActionTypes.SIGN_IN_EMPLOYEE_FAILURE, + payload: error, +}); + +export function loginEmployee() { + return { + type: EmployeeActionTypes.AUTHORIZING_EMPLOYEE_REQUEST, + payload:"text" + } +} +export function loginEmployeeSuccess(technician) { + return { + type: EmployeeActionTypes.AUTHORIZING_EMPLOYEE_SUCCESS, + payload: technician + } +} diff --git a/redux/employee/employee.reducer.js b/redux/employee/employee.reducer.js new file mode 100644 index 0000000..7a327f8 --- /dev/null +++ b/redux/employee/employee.reducer.js @@ -0,0 +1,36 @@ +import EmployeeActionTypes from "./employee.types"; + +const INITIAL_STATE = { + currentEmployee: { + authorized: null, + }, + employeeSigningIn: false, + error: null, +}; + +const employeeReducer = (state = INITIAL_STATE, action) => { + switch (action.type) { + case EmployeeActionTypes.SIGN_IN_EMPLOYEE_START: + return { + ...state, + employeeSigningIn: true, + error: null, + }; + case EmployeeActionTypes.SIGN_IN_EMPLOYEE_SUCCESS: + return { + ...state, + currentEmployee: action.payload, + error: null, + }; + case EmployeeActionTypes.SIGN_OUT_EMPLOYEE_SUCCESS: + return { + ...state, + currentEmployee: { authorized: false }, + error: null, + }; + default: + return state; + } +}; + +export default employeeReducer; diff --git a/redux/employee/employee.sagas.js b/redux/employee/employee.sagas.js new file mode 100644 index 0000000..fc04e7d --- /dev/null +++ b/redux/employee/employee.sagas.js @@ -0,0 +1,42 @@ +import EmployeeActionTypes from "./employee.types"; +import { + signInEmployeeStart, + signInEmployeeSuccess, + signInEmployeeFailure, +} from "./employee.actions"; +import { all, call, put, takeLatest } from "redux-saga/effects"; +import { logImEXEvent } from "../../firebase/firebase.analytics"; +import { selectBodyshop } from "../user/user.selectors"; +import axios from "axios"; + +export function* onSignInEmployeeStart() { + yield takeLatest( + EmployeeActionTypes.SIGN_IN_EMPLOYEE_START, + signInWithEmployeeId + ); +} +export function* signInWithEmployeeId({ payload: { employeeid, pin } }) { + try { + logImEXEvent("redux_sign_in_employee_attempt"); + //console.loging + const bodyshop = yield select(selectBodyshop); + const response = yield call(axios.post, "/tech/login", { + shopid: bodyshop.id, + employeeid: employeeid, + pin: pin, + }); + const { valid, technician, error } = response.data; + + if (valid) { + yield put(signInEmployeeSuccess(technician)); + } else { + yield put(signInEmployeeFailure(error)); + } + } catch (error) { + yield put(signInEmployeeFailure(error)); + } +} + +export function* employeeSagas() { + yield all([call(onSignInEmployeeStart)]); +} diff --git a/redux/employee/employee.selectors.js b/redux/employee/employee.selectors.js new file mode 100644 index 0000000..84790c8 --- /dev/null +++ b/redux/employee/employee.selectors.js @@ -0,0 +1,12 @@ +import { createSelector } from "reselect"; + +const selectEmployee = (state) => state.employee; + +export const selectCurrentEmployee = createSelector( + [selectEmployee], + (employee) => employee.currentEmployee + ); +export const selectSigningIn = createSelector( + [selectEmployee], + (employee) => employee.signingIn + ); \ No newline at end of file diff --git a/redux/employee/employee.types.js b/redux/employee/employee.types.js new file mode 100644 index 0000000..eb03657 --- /dev/null +++ b/redux/employee/employee.types.js @@ -0,0 +1,17 @@ +const EmployeeActionTypes = { + AUTHORIZING_EMPLOYEE_REQUEST:"AUTHORIZING_EMPLOYEE_REQUEST", + AUTHORIZING_EMPLOYEE_SUCCESS:"AUTHORIZING_EMPLOYEE_SUCCESS", + AUTHORIZING_EMPLOYEE_SUCCESS:"AUTHORIZING_EMPLOYEE_FAILURE", + SET_CURRENT_EMPLOYEE: "SET_CURRENT_EMPLOYEE", + SIGN_IN_EMPLOYEE_SUCCESS: "SIGN_IN_EMPLOYEE_SUCCESS", + SIGN_IN_EMPLOYEE_FAILURE: "SIGN_IN_EMPLOYEE_FAILURE", + SIGN_IN_EMPLOYEE_START: "SIGN_IN_EMPLOYEE_START", + CHECK_EMPLOYEE_SESSION: "CHECK_EMPLOYEE_SESSION", + SIGN_OUT_EMPLOYEE_START: "SIGN_OUT_EMPLOYEE_START", + SIGN_OUT_EMPLOYEE_SUCCESS: "SIGN_OUT_EMPLOYEE_SUCCESS", + SIGN_OUT_EMPLOYEE_FAILURE: "SIGN_OUT_EMPLOYEE_FAILURE", + UNAUTHORIZED_EMPLOYEE: "UNAUTHORIZED_EMPLOYEE", + UPDATE_EMPLOYEE_DETAILS: "UPDATE_EMPLOYEE_DETAILS", + UPDATE_EMPLOYEE_DETAILS_SUCCESS: "UPDATE_EMPLOYEE_DETAILS_SUCCESS", + }; + export default EmployeeActionTypes; \ No newline at end of file From f8a0992efe2dbbe8fddc354f21be8940a37dbb03 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 13 Apr 2023 13:34:20 -0400 Subject: [PATCH 005/105] adding reducer and saga for employee --- .../screen-tech-sign-in.component.jsx | 20 ++++++++++++++----- redux/employee/employee.actions.js | 6 ++++++ redux/root.reducer.js | 3 +++ redux/root.saga.js | 3 ++- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/components/screen-tech-sign-in/screen-tech-sign-in.component.jsx b/components/screen-tech-sign-in/screen-tech-sign-in.component.jsx index 6c257db..1680bb3 100644 --- a/components/screen-tech-sign-in/screen-tech-sign-in.component.jsx +++ b/components/screen-tech-sign-in/screen-tech-sign-in.component.jsx @@ -5,20 +5,30 @@ import { Button, TextInput } from "react-native-paper"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; - +import { signInEmployeeStart } from "../../redux/employee/employee.actions"; +import { createStructuredSelector } from "reselect"; +import { + selectCurrentEmployee, selectSigningIn +} from "../../redux/employee/employee.selectors"; //TODO JF add props -const mapStateToProps = (state) => ({}); +const mapStateToProps = createStructuredSelector({ + currentEmployee: selectCurrentEmployee, + signingIn: selectSigningIn, +}); //TODO JF add prop functions to call dispatch with actions -const mapDispatchToProps = {}; +const mapDispatchToProps = (dispatch) => ({ + signInEmployeeStart: (employeeId, pin) => + dispatch(signInEmployeeStart({ employeeId, pin })), +}); -export function TechSignIn({ employeeSignInStart, employeeSigningIn }) { +export function TechSignIn({ signInEmployeeStart, employeeSigningIn }) { const { t } = useTranslation(); //TODO add call to dispatch action const formSubmit = (values) => { const { employeeId, pin } = values; - // techSignInStart(employeeId, pin); + signInEmployeeStart(employeeId, pin); }; return ( diff --git a/redux/employee/employee.actions.js b/redux/employee/employee.actions.js index c140d23..1f58d0e 100644 --- a/redux/employee/employee.actions.js +++ b/redux/employee/employee.actions.js @@ -27,3 +27,9 @@ export function loginEmployeeSuccess(technician) { payload: technician } } +export function loginEmployeeFal(error) { + return { + type: EmployeeActionTypes.AUTHORIZING_EMPLOYEE_FALURE, + error: error + } +} diff --git a/redux/root.reducer.js b/redux/root.reducer.js index 8ef298d..dc89441 100644 --- a/redux/root.reducer.js +++ b/redux/root.reducer.js @@ -4,6 +4,7 @@ import { persistReducer } from "redux-persist"; import appReducer from "./app/app.reducer"; import photosReducer from "./photos/photos.reducer"; import userReducer from "./user/user.reducer"; +import employeeReducer from './employee/employee.reducer'; const persistConfig = { key: "root", @@ -12,10 +13,12 @@ const persistConfig = { blacklist: ["user"], }; +//ADDED JF employee: employeeReducer const rootReducer = combineReducers({ user: userReducer, app: appReducer, photos: photosReducer, + employee: employeeReducer, }); export default persistReducer(persistConfig, rootReducer); diff --git a/redux/root.saga.js b/redux/root.saga.js index b2e2da1..c217084 100644 --- a/redux/root.saga.js +++ b/redux/root.saga.js @@ -2,7 +2,8 @@ import { all, call } from "redux-saga/effects"; import { appSagas } from "./app/app.sagas"; import { photosSagas } from "./photos/photos.sagas"; import { userSagas } from "./user/user.sagas"; +import { employeeSagas } from "./employee/employee.sagas"; export default function* rootSaga() { - yield all([call(userSagas), call(appSagas), call(photosSagas)]); + yield all([call(userSagas), call(appSagas), call(photosSagas), call(employeeSagas)]); } From 20406c1071b38b5c56381bf57c0d2f86f8ac8879 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Thu, 13 Apr 2023 10:52:22 -0700 Subject: [PATCH 006/105] Add logger and resolve log in issue. --- redux/employee/employee.sagas.js | 7 ++++--- redux/store.js | 12 ++++++------ util/CleanAxios.js | 10 +++++----- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/redux/employee/employee.sagas.js b/redux/employee/employee.sagas.js index fc04e7d..0b1e7c1 100644 --- a/redux/employee/employee.sagas.js +++ b/redux/employee/employee.sagas.js @@ -4,7 +4,7 @@ import { signInEmployeeSuccess, signInEmployeeFailure, } from "./employee.actions"; -import { all, call, put, takeLatest } from "redux-saga/effects"; +import { all, call, put, select, takeLatest } from "redux-saga/effects"; import { logImEXEvent } from "../../firebase/firebase.analytics"; import { selectBodyshop } from "../user/user.selectors"; import axios from "axios"; @@ -15,14 +15,15 @@ export function* onSignInEmployeeStart() { signInWithEmployeeId ); } -export function* signInWithEmployeeId({ payload: { employeeid, pin } }) { +export function* signInWithEmployeeId({ payload: { employeeId, pin } }) { try { logImEXEvent("redux_sign_in_employee_attempt"); //console.loging + console.log("Saga", employeeId, pin, pin); const bodyshop = yield select(selectBodyshop); const response = yield call(axios.post, "/tech/login", { shopid: bodyshop.id, - employeeid: employeeid, + employeeid: employeeId, pin: pin, }); const { valid, technician, error } = response.data; diff --git a/redux/store.js b/redux/store.js index f4aed43..acaab0c 100644 --- a/redux/store.js +++ b/redux/store.js @@ -1,6 +1,6 @@ import { applyMiddleware, compose, createStore } from "redux"; import { persistStore } from "redux-persist"; -//import { createLogger } from "redux-logger"; +import { createLogger } from "redux-logger"; import createSagaMiddleware from "redux-saga"; import rootReducer from "./root.reducer"; import rootSaga from "./root.saga"; @@ -9,11 +9,11 @@ const sagaMiddleWare = createSagaMiddleware(); const middlewares = [sagaMiddleWare]; // if (process.env.NODE_ENV === "development") { -// middlewares.push( -// createLogger({ -// collapsed: true, -// }) -// ); +middlewares.push( + createLogger({ + collapsed: true, + }) +); // } //Add in for React Native Debugger. diff --git a/util/CleanAxios.js b/util/CleanAxios.js index de36f24..4c15ca2 100644 --- a/util/CleanAxios.js +++ b/util/CleanAxios.js @@ -1,10 +1,10 @@ import axios from "axios"; import { auth } from "../firebase/firebase.utils"; - -if (process.env.NODE_ENV === "production") { - axios.defaults.baseURL = - process.env.REACT_APP_AXIOS_BASE_API_URL || "https://api.imex.online/"; -} +import env from "../env"; +//if (process.env.NODE_ENV === "production") { +axios.defaults.baseURL = "https://api.test.imex.online/"; +//env.REACT_APP_AXIOS_BASE_API_URL || "https://api.imex.online/"; +//} export const axiosAuthInterceptorId = axios.interceptors.request.use( async (config) => { From 0ff1806b0c2e16d5d062d45ddf565cdc3450a7b7 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Fri, 14 Apr 2023 14:36:00 -0400 Subject: [PATCH 007/105] updated common.json to have matching objs --- translations/es-MX/common.json | 21 +++++++++++++++++++++ translations/fr-CA/common.json | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/translations/es-MX/common.json b/translations/es-MX/common.json index f883e6f..b59a837 100644 --- a/translations/es-MX/common.json +++ b/translations/es-MX/common.json @@ -317,6 +317,27 @@ "fields": { "employeeid": "", "pin": "" + }, + "titles": { + "signin": "" + } + }, + "timeticketbrowser": { + "actions": { + "refresh": "", + "upload": "", + "activetickets": "", + "detail": "", + "notickets": "" + }, + "labels": { + "converting": "", + "selectjob": "", + "selectticketassetselector": "", + "uploading": "" + }, + "titles": { + "timeticketbrowsertab": "" } } } diff --git a/translations/fr-CA/common.json b/translations/fr-CA/common.json index 30b1675..35440bc 100644 --- a/translations/fr-CA/common.json +++ b/translations/fr-CA/common.json @@ -317,6 +317,27 @@ "fields": { "employeeid": "", "pin": "" + }, + "titles": { + "signin": "" + } + }, + "timeticketbrowser": { + "actions": { + "refresh": "", + "upload": "", + "activetickets": "", + "detail": "", + "notickets": "" + }, + "labels": { + "converting": "", + "selectjob": "", + "selectticketassetselector": "", + "uploading": "" + }, + "titles": { + "timeticketbrowsertab": "" } } } From 73e975af93cdac21313a6fef2496755be31193c4 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Fri, 14 Apr 2023 15:07:37 -0400 Subject: [PATCH 008/105] Updated names to all use employee --- .../screen-employee-sign-in.component.jsx} | 10 +++++----- components/screen-main/screen-main.component.jsx | 9 +++++---- translations/en-US/common.json | 4 ++-- translations/es-MX/common.json | 4 ++-- translations/fr-CA/common.json | 4 ++-- 5 files changed, 16 insertions(+), 15 deletions(-) rename components/{screen-tech-sign-in/screen-tech-sign-in.component.jsx => screen-employee-sign-in/screen-employee-sign-in.component.jsx} (87%) diff --git a/components/screen-tech-sign-in/screen-tech-sign-in.component.jsx b/components/screen-employee-sign-in/screen-employee-sign-in.component.jsx similarity index 87% rename from components/screen-tech-sign-in/screen-tech-sign-in.component.jsx rename to components/screen-employee-sign-in/screen-employee-sign-in.component.jsx index 1680bb3..9472f13 100644 --- a/components/screen-tech-sign-in/screen-tech-sign-in.component.jsx +++ b/components/screen-employee-sign-in/screen-employee-sign-in.component.jsx @@ -22,7 +22,7 @@ const mapDispatchToProps = (dispatch) => ({ dispatch(signInEmployeeStart({ employeeId, pin })), }); -export function TechSignIn({ signInEmployeeStart, employeeSigningIn }) { +export function EmployeeSignIn({ signInEmployeeStart, employeeSigningIn }) { const { t } = useTranslation(); //TODO add call to dispatch action @@ -41,7 +41,7 @@ export function TechSignIn({ signInEmployeeStart, employeeSigningIn }) { {({ handleChange, handleBlur, handleSubmit, values }) => ( - {t("techsignin.actions.techsignin")} + {t("employeesignin.actions.employeesignin")} )} @@ -87,4 +87,4 @@ const localStyles = StyleSheet.create({ }, }); -export default connect(mapStateToProps, mapDispatchToProps)(TechSignIn); +export default connect(mapStateToProps, mapDispatchToProps)(EmployeeSignIn); diff --git a/components/screen-main/screen-main.component.jsx b/components/screen-main/screen-main.component.jsx index 0f3254b..0d97678 100644 --- a/components/screen-main/screen-main.component.jsx +++ b/components/screen-main/screen-main.component.jsx @@ -25,8 +25,9 @@ import ScreenMediaBrowser from "../screen-media-browser/screen-media-browser.com import ScreenSettingsComponent from "../screen-settings/screen-settings.component"; 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 TechSignIn from "../screen-tech-sign-in/screen-tech-sign-in.component"; +import EmployeeSignIn from "../screen-employee-sign-in/screen-employee-sign-in.component"; const ActiveJobStack = createNativeStackNavigator(); const MoreStack = createNativeStackNavigator(); @@ -113,11 +114,11 @@ const MoreStackNavigator = () => ( const TimeTicketBrowserStackNavigator = () => ( ({ - title: i18n.t("techsignin.titles.signin"), + title: i18n.t("employeesignin.titles.signin"), })} - component={TechSignIn} + component={EmployeeSignIn} /> {/* Date: Fri, 14 Apr 2023 15:09:52 -0400 Subject: [PATCH 009/105] Updated signin to use Employee --- translations/en-US/common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translations/en-US/common.json b/translations/en-US/common.json index 2a4f9e7..c042eef 100644 --- a/translations/en-US/common.json +++ b/translations/en-US/common.json @@ -319,7 +319,7 @@ "pin": "PIN" }, "titles": { - "signin": "Tech Sign In" + "signin": "Employee Sign In" } }, "timeticketbrowser": { From bd0ba5c0df3a3dae1b92ded35b13757aca3f4bf0 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Wed, 19 Apr 2023 11:00:01 -0400 Subject: [PATCH 010/105] Updated Employee Action Types --- redux/employee/employee.types.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redux/employee/employee.types.js b/redux/employee/employee.types.js index eb03657..a8fe7ad 100644 --- a/redux/employee/employee.types.js +++ b/redux/employee/employee.types.js @@ -1,7 +1,7 @@ const EmployeeActionTypes = { AUTHORIZING_EMPLOYEE_REQUEST:"AUTHORIZING_EMPLOYEE_REQUEST", AUTHORIZING_EMPLOYEE_SUCCESS:"AUTHORIZING_EMPLOYEE_SUCCESS", - AUTHORIZING_EMPLOYEE_SUCCESS:"AUTHORIZING_EMPLOYEE_FAILURE", + AUTHORIZING_EMPLOYEE_FAILURE:"AUTHORIZING_EMPLOYEE_FAILURE", SET_CURRENT_EMPLOYEE: "SET_CURRENT_EMPLOYEE", SIGN_IN_EMPLOYEE_SUCCESS: "SIGN_IN_EMPLOYEE_SUCCESS", SIGN_IN_EMPLOYEE_FAILURE: "SIGN_IN_EMPLOYEE_FAILURE", From 95a53222e772dbd8b2dcb9acaedb0ec937e854bc Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 20 Apr 2023 10:38:57 -0400 Subject: [PATCH 011/105] Updated employee login --- .../screen-employee-sign-in.component.jsx | 31 +++++++++++------ redux/employee/employee.actions.js | 34 ++++++------------- redux/employee/employee.reducer.js | 23 ++++++++----- redux/employee/employee.sagas.js | 14 ++++---- redux/employee/employee.selectors.js | 6 +++- redux/employee/employee.types.js | 28 +++++++-------- 6 files changed, 69 insertions(+), 67 deletions(-) diff --git a/components/screen-employee-sign-in/screen-employee-sign-in.component.jsx b/components/screen-employee-sign-in/screen-employee-sign-in.component.jsx index 9472f13..faf2eab 100644 --- a/components/screen-employee-sign-in/screen-employee-sign-in.component.jsx +++ b/components/screen-employee-sign-in/screen-employee-sign-in.component.jsx @@ -5,34 +5,40 @@ import { Button, TextInput } from "react-native-paper"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; -import { signInEmployeeStart } from "../../redux/employee/employee.actions"; +import { employeeSignInStart } from "../../redux/employee/employee.actions"; import { createStructuredSelector } from "reselect"; import { - selectCurrentEmployee, selectSigningIn + selectCurrentEmployee, + selectSigningIn, + selectSignInError } from "../../redux/employee/employee.selectors"; -//TODO JF add props -const mapStateToProps = createStructuredSelector({ + +import ErrorDisplay from "../error-display/error-display.component"; +// import Timer from "../../util/timer"; + +const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, signingIn: selectSigningIn, + signingError: selectSignInError, }); -//TODO JF add prop functions to call dispatch with actions +// JF add prop functions to call dispatch with actions const mapDispatchToProps = (dispatch) => ({ - signInEmployeeStart: (employeeId, pin) => - dispatch(signInEmployeeStart({ employeeId, pin })), + employeeSignInStart: (employeeId, pin) => dispatch(employeeSignInStart({ employeeId, pin })), }); -export function EmployeeSignIn({ signInEmployeeStart, employeeSigningIn }) { +export function EmployeeSignIn({currentEmployee,signingError, signingIn, employeeSignInStart }) { const { t } = useTranslation(); -//TODO add call to dispatch action + //TODO add call to dispatch action const formSubmit = (values) => { const { employeeId, pin } = values; - signInEmployeeStart(employeeId, pin); + employeeSignInStart(employeeId, pin); }; return ( + {/* {currentEmployee ? : null} */} + {signingError && ( + + )} + + + + ); +} + + function start() { + setTimerOn(true); +} + function stop() { + setTimerOn(false); +} + function reset() { + setTime(300000); +} + + +// The data/time we want to countdown to +// var countDownDate = new Date(moment.).getTime(); +// // Run myfunc every second +// var myfunc = setInterval(function() { + +// var now = new Date().getTime(); +// var timeleft = countDownDate - now; + +// // Calculating the days, hours, minutes and seconds left +// var days = Math.floor(timeleft / (1000 * 60 * 60 * 24)); +// var hours = Math.floor((timeleft % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); +// var minutes = Math.floor((timeleft % (1000 * 60 * 60)) / (1000 * 60)); +// var seconds = Math.floor((timeleft % (1000 * 60)) / 1000); + +// // Result is output to the specific element +// document.getElementById("days").innerHTML = days + "d " +// document.getElementById("hours").innerHTML = hours + "h " +// document.getElementById("mins").innerHTML = minutes + "m " +// document.getElementById("secs").innerHTML = seconds + "s " + +// // Display the message when countdown is over +// if (timeleft < 0) { +// clearInterval(myfunc); +// document.getElementById("days").innerHTML = "" +// document.getElementById("hours").innerHTML = "" +// document.getElementById("mins").innerHTML = "" +// document.getElementById("secs").innerHTML = "" +// document.getElementById("end").innerHTML = "TIME UP!!"; +// } +// }, 1000); From f3384d4e36cae44c61824afdcebb23ae7a921570 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 20 Apr 2023 22:38:22 -0400 Subject: [PATCH 013/105] Added login and logout --- .../create-time-ticket-button.component.jsx | 24 +++++++ .../employee-sign-out-button.component.jsx | 25 +++++++ .../screen-ap-time-ticket-list.component.jsx | 11 +++ .../screen-employee-sign-in.component.jsx | 19 +++-- .../screen-main/screen-main.component.jsx | 69 ++++++++++++++----- redux/employee/employee.actions.js | 1 - redux/employee/employee.selectors.js | 2 +- redux/root.reducer.js | 1 - translations/en-US/common.json | 6 +- translations/es-MX/common.json | 6 +- translations/fr-CA/common.json | 6 +- 11 files changed, 133 insertions(+), 37 deletions(-) create mode 100644 components/Buttons/create-time-ticket-button.component.jsx create mode 100644 components/Buttons/employee-sign-out-button.component.jsx create mode 100644 components/screen-ap-time-ticket-list/screen-ap-time-ticket-list.component.jsx diff --git a/components/Buttons/create-time-ticket-button.component.jsx b/components/Buttons/create-time-ticket-button.component.jsx new file mode 100644 index 0000000..0063bd8 --- /dev/null +++ b/components/Buttons/create-time-ticket-button.component.jsx @@ -0,0 +1,24 @@ +import React from "react"; +import { Text } from "react-native"; +import { Button } from "react-native-paper"; +import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; + +// const mapDispatchToProps = (dispatch) => ({ +// signOut: () => dispatch(employeeSignOut()), +// }); + +export function AddTimeTicketButton({ doOnPress }) { + const { t } = useTranslation(); + return ( + + ); +} +export default connect(null, null)(AddTimeTicketButton); \ No newline at end of file diff --git a/components/Buttons/employee-sign-out-button.component.jsx b/components/Buttons/employee-sign-out-button.component.jsx new file mode 100644 index 0000000..6660b5c --- /dev/null +++ b/components/Buttons/employee-sign-out-button.component.jsx @@ -0,0 +1,25 @@ +import React from "react"; +import { Text } from "react-native"; +import { Button } from "react-native-paper"; +import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; +import { employeeSignOut } from "../../redux/employee/employee.actions"; + +const mapDispatchToProps = (dispatch) => ({ + signOut: () => dispatch(employeeSignOut()), +}); + +export function SignOutButton({ signOut }) { + const { t } = useTranslation(); + return ( + + ); +} +export default connect(null, mapDispatchToProps)(SignOutButton); diff --git a/components/screen-ap-time-ticket-list/screen-ap-time-ticket-list.component.jsx b/components/screen-ap-time-ticket-list/screen-ap-time-ticket-list.component.jsx new file mode 100644 index 0000000..ea2ab50 --- /dev/null +++ b/components/screen-ap-time-ticket-list/screen-ap-time-ticket-list.component.jsx @@ -0,0 +1,11 @@ +import React from "react"; +import { View, Text } from "react-native"; + +export default function ScreenApTimeTicketList() { + return ( + + Time Ticket List goes here + + + ); +} diff --git a/components/screen-employee-sign-in/screen-employee-sign-in.component.jsx b/components/screen-employee-sign-in/screen-employee-sign-in.component.jsx index faf2eab..9b7398e 100644 --- a/components/screen-employee-sign-in/screen-employee-sign-in.component.jsx +++ b/components/screen-employee-sign-in/screen-employee-sign-in.component.jsx @@ -10,11 +10,10 @@ import { createStructuredSelector } from "reselect"; import { selectCurrentEmployee, selectSigningIn, - selectSignInError + selectSignInError, } from "../../redux/employee/employee.selectors"; import ErrorDisplay from "../error-display/error-display.component"; -// import Timer from "../../util/timer"; const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, @@ -22,15 +21,18 @@ const mapStateToProps = createStructuredSelector({ signingError: selectSignInError, }); -// JF add prop functions to call dispatch with actions const mapDispatchToProps = (dispatch) => ({ - employeeSignInStart: (employeeId, pin) => dispatch(employeeSignInStart({ employeeId, pin })), + employeeSignInStart: (employeeId, pin) => + dispatch(employeeSignInStart({ employeeId, pin })), }); -export function EmployeeSignIn({currentEmployee,signingError, signingIn, employeeSignInStart }) { +export function EmployeeSignIn({ + signingError, + signingIn, + employeeSignInStart, +}) { const { t } = useTranslation(); - //TODO add call to dispatch action const formSubmit = (values) => { const { employeeId, pin } = values; employeeSignInStart(employeeId, pin); @@ -38,7 +40,6 @@ export function EmployeeSignIn({currentEmployee,signingError, signingIn, employe return ( - {/* {currentEmployee ? : null} */} - {signingError && ( - - )} + {signingError && } - )} + ) +}} From 71d3b43f2069110b842ef3a0e83a855574ac3dbd Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Fri, 21 Apr 2023 12:43:33 -0400 Subject: [PATCH 016/105] fix case of employee not auto logout on close app --- .../screen-main/screen-main.component.jsx | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/components/screen-main/screen-main.component.jsx b/components/screen-main/screen-main.component.jsx index d66a6f5..2fdea5b 100644 --- a/components/screen-main/screen-main.component.jsx +++ b/components/screen-main/screen-main.component.jsx @@ -13,8 +13,15 @@ import { logImEXEvent } from "../../firebase/firebase.analytics"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { setCameraJob, setCameraJobId } from "../../redux/app/app.actions"; -import { checkUserSession, emailSignInStart, signOutStart } from "../../redux/user/user.actions"; -import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors"; +import { + checkUserSession, + emailSignInStart, + signOutStart, +} from "../../redux/user/user.actions"; +import { + selectBodyshop, + selectCurrentUser, +} from "../../redux/user/user.selectors"; import { employeeSignOut } from "../../redux/employee/employee.actions"; import { selectCurrentEmployee } from "../../redux/employee/employee.selectors"; @@ -123,13 +130,22 @@ const TimeTicketBrowserStackNavigator = connect( const appState = useRef(AppState.currentState); useEffect(() => { const subscription = AppState.addEventListener("change", (nextAppState) => { - if ( - appState.current.match(/inactive|background/) && - nextAppState === "active" - ) { - // console.log("App has come to the foreground"); + // console.log("oldAppState", appState.current); + // console.log("nextAppState", nextAppState); + // if ( appState.current.match(/inactive|background/) && nextAppState === "active" + // ) { console.log("App has come to the foreground"); //signOut(); } + // if (appState.current.match(/active/) && nextAppState === "inactive") { + // console.log("App is about to be inactive"); + // } + + if ( appState.current.match(/active|inactive/) && nextAppState === "background" + ) {// 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); }); From 61a74be0b01192041ad906a0f83e353ef4d7440e Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 4 May 2023 13:47:22 -0400 Subject: [PATCH 017/105] added queries --- graphql/employees.queries.js | 54 ++++++++++++++++++++++++++++++++ graphql/timetickets.queries.js | 52 ++++++++++++++++++++++++++++++ redux/employee/employee.types.js | 3 ++ 3 files changed, 109 insertions(+) create mode 100644 graphql/employees.queries.js create mode 100644 graphql/timetickets.queries.js diff --git a/graphql/employees.queries.js b/graphql/employees.queries.js new file mode 100644 index 0000000..8cd59b7 --- /dev/null +++ b/graphql/employees.queries.js @@ -0,0 +1,54 @@ +import gql from "graphql-tag"; + +export const QUERY_EMPLOYEES = gql` + query QUERY_EMPLOYEES { + employees(order_by: { employee_number: asc }) { + last_name + id + first_name + flat_rate + employee_number + } + } +`; +export const QUERY_EMPLOYEE_BY_ID = gql` + query QUERY_EMPLOYEE_BY_ID($id: uuid!) { + employees_by_pk(id: $id) { + last_name + id + first_name + employee_number + active + termination_date + hire_date + flat_rate + rates + pin + user_email + external_id + employee_vacations(order_by: { start: desc }) { + id + start + end + } + } + } +`; + +export const QUERY_ACTIVE_EMPLOYEES = gql` + query QUERY_ACTIVE_EMPLOYEES { + employees(where: { active: { _eq: true } }) { + last_name + id + first_name + employee_number + active + termination_date + hire_date + flat_rate + rates + pin + user_email + } + } +`; \ No newline at end of file diff --git a/graphql/timetickets.queries.js b/graphql/timetickets.queries.js new file mode 100644 index 0000000..5fe94ae --- /dev/null +++ b/graphql/timetickets.queries.js @@ -0,0 +1,52 @@ +import gql from "graphql-tag"; + + + +export const INSERT_NEW_TIME_TICKET = gql` + mutation INSERT_NEW_TIME_TICKET( + $timeTicketInput: [timetickets_insert_input!]! + ) { + insert_timetickets(objects: $timeTicketInput) { + returning { + id + clockon + clockoff + employeeid + productivehrs + actualhrs + ciecacode + date + memo + flat_rate + } + } + } +`; + +export const UPDATE_TIME_TICKET = gql` + mutation UPDATE_TIME_TICKET( + $timeticketId: uuid! + $timeticket: timetickets_set_input! + ) { + update_timetickets( + where: { id: { _eq: $timeticketId } } + _set: $timeticket + ) { + returning { + id + clockon + clockoff + employeeid + productivehrs + actualhrs + ciecacode + created_at + updated_at + jobid + date + flat_rate + memo + } + } + } +`; \ No newline at end of file diff --git a/redux/employee/employee.types.js b/redux/employee/employee.types.js index cea3d6f..2c7b378 100644 --- a/redux/employee/employee.types.js +++ b/redux/employee/employee.types.js @@ -6,6 +6,9 @@ const EmployeeActionTypes = { EMPLOYEE_AUTHORIZING_SUCCESS: "EMPLOYEE_AUTHORIZING_SUCCESS", EMPLOYEE_AUTHORIZING_FAILURE: "EMPLOYEE_AUTHORIZING_FAILURE", EMPLOYEE_SIGN_OUT: "EMPLOYEE_SIGN_OUT", + EMPLOYEE_CREATE_TIME_TICKET_START: "EMPLOYEE_CREATE_TIME_TICKET_START", + EMPLOYEE_CREATE_TIME_TICKET_SUCCESS: "EMPLOYEE_CREATE_TIME_TICKET_SUCCESS", + EMPLOYEE_CREATE_TIME_TICKET_FAILURE: "EMPLOYEE_CREATE_TIME_TICKET_FAILURE", EMPLOYEE_CHECK_SESSION: "EMPLOYEE_CHECK_SESSION", EMPLOYEE_SET_CURRENT: "EMPLOYEE_SET_CURRENT" From ee476c89c4afb1da2ae73913e42935a6eb5c7e0f Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 4 May 2023 13:47:59 -0400 Subject: [PATCH 018/105] Added react-native-element-dropdown --- package.json | 1 + yarn.lock | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/package.json b/package.json index a6035d5..2b2edcc 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "react-native": "0.71.6", "react-native-dnd-board": "hungga1711/react-native-dnd-board#13/head", "react-native-draggable-flatlist": "^3.1.2", + "react-native-element-dropdown": "^2.9.0", "react-native-gesture-handler": "^2.9.0", "react-native-image-gallery": "^2.1.5", "react-native-image-viewing": "^0.2.2", diff --git a/yarn.lock b/yarn.lock index 998c833..38c93c0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7937,6 +7937,13 @@ react-native-draggable-flatlist@^3.1.2: resolved "https://registry.yarnpkg.com/react-native-draggable-flatlist/-/react-native-draggable-flatlist-3.1.2.tgz#b66538007f645ccd851c729d4b8a8f7e07666d3f" integrity sha512-cqBR+lZktTqHY/J7V0aq+TZNkuqeILxwZ5bBXKndokwH4qvZl7ifijM7LlfWhfhU1/pzjketTsX7P2zyojfAaQ== +react-native-element-dropdown@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/react-native-element-dropdown/-/react-native-element-dropdown-2.9.0.tgz#c218ab512bd8be69fa0ac70462293863f8cfd527" + integrity sha512-2Y/bmoFPTdKOUXbYloEKpMTWYE2VHrvva/5tgEuHqAlfAtGGr3r/ob0L0YYH1am5N0n1PKo3+eLf0c79QUSzYw== + dependencies: + lodash "^4.17.21" + react-native-gesture-handler@^2.4.0, react-native-gesture-handler@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-2.9.0.tgz#2f63812e523c646f25b9ad660fc6f75948e51241" From fbababc26dceb7a40ce849e5de3675f5b0cedb47 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Fri, 5 May 2023 09:20:23 -0400 Subject: [PATCH 019/105] added selectCostCenter.jsx --- components/Selects/select-cost-center.jsx | 95 +++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 components/Selects/select-cost-center.jsx diff --git a/components/Selects/select-cost-center.jsx b/components/Selects/select-cost-center.jsx new file mode 100644 index 0000000..4bf0795 --- /dev/null +++ b/components/Selects/select-cost-center.jsx @@ -0,0 +1,95 @@ +import React, { useState } from "react"; +import { StyleSheet, Text, View } from "react-native"; +import { Dropdown } from "react-native-element-dropdown"; +import { connect } from "react-redux"; + +const data = [ + { label: "Item 1", value: "1" }, + { label: "Item 2", value: "2" }, + { label: "Item 3", value: "3" }, + { label: "Item 4", value: "4" }, + { label: "Item 5", value: "5" }, + { label: "Item 6", value: "6" }, + { label: "Item 7", value: "7" }, + { label: "Item 8", value: "8" }, +]; + +export function SelectCostCenter(props) { + const [value, setValue] = useState(null); + const [isFocus, setIsFocus] = useState(false); + + + return ( + + setIsFocus(true)} + onBlur={() => setIsFocus(false)} + onChange={(item) => { + setValue(item.value); + setIsFocus(false); + }} + /> + + ); +} + +const mapStateToProps = (state) => ({}); + +const mapDispatchToProps = {}; + +export default connect(mapStateToProps, mapDispatchToProps)(SelectCostCenter); + +const styles = StyleSheet.create({ + container: { + backgroundColor: "white", + padding: 16, + justifyContent: "center", + alignContent: "center", + }, + dropdown: { + height: 50, + borderColor: "gray", + borderWidth: 0.5, + borderRadius: 8, + paddingHorizontal: 8, + }, + icon: { + marginRight: 5, + }, + label: { + position: "absolute", + backgroundColor: "white", + left: 22, + top: 8, + zIndex: 999, + paddingHorizontal: 8, + fontSize: 14, + }, + placeholderStyle: { + fontSize: 16, + }, + selectedTextStyle: { + fontSize: 16, + }, + iconStyle: { + width: 20, + height: 20, + }, + inputSearchStyle: { + height: 40, + fontSize: 16, + }, +}); From 957c0c60705af0eb4bc28e0a11785d131b446196 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Fri, 5 May 2023 09:21:54 -0400 Subject: [PATCH 020/105] added screen-time-ticket-create.component.jsx --- .../screen-time-ticket-create.component.jsx | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 components/time-ticket/screen-time-ticket-create.component.jsx diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx new file mode 100644 index 0000000..398a43b --- /dev/null +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -0,0 +1,125 @@ +import { Formik } from "formik"; +import React from "react"; +import { StyleSheet, Text } from "react-native"; +import { useTranslation } from "react-i18next"; +import { View, ScrollView } from "react-native"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { Button, Dialog, TextInput } from "react-native-paper"; +import { QUERY_EMPLOYEE_BY_ID } from "../../graphql/employees.queries"; +//import SelectDropdown from 'react-native-select-dropdown'; +import { SelectCostCenter } from "../Selects/select-cost-center"; +import { selectCurrentEmployee } from "../../redux/employee/employee.selectors"; +//import {DateTimePicker} from "expo"; + +//TODO add props needed for call +const mapStateToProps = createStructuredSelector({ + currentEmployee: selectCurrentEmployee, +}); + +export function TimeTicketCreate() { + const { t } = useTranslation(); + + const formSubmit = (values) => { + Dialog.alert({ content:
{JSON.stringify(values, null, 2)}
}); + //TODO update with start call for create time ticket + }; + + return ( + + + + {({ handleChange, handleBlur, handleSubmit, values }) => ( + + + + + + + + + + + )} + + + + + + + ); +} + +export default connect(null, null)(TimeTicketCreate); + +const localStyles = StyleSheet.create({ + content: { + display: "flex", + flex: 1 + }, + topTimeTicketContainer: { + }, + bottomTimeTicketContainer: { + }, + input: { + }, +}); From 57f7adac6eaec739c4bdf5f6b0168d7101e5e9e0 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Fri, 5 May 2023 09:23:01 -0400 Subject: [PATCH 021/105] added navigation to new screentimeticketcreate --- .../create-time-ticket-button.component.jsx | 9 +++- .../screen-main/screen-main.component.jsx | 41 ++++++++++++------- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/components/Buttons/create-time-ticket-button.component.jsx b/components/Buttons/create-time-ticket-button.component.jsx index 0063bd8..df87a22 100644 --- a/components/Buttons/create-time-ticket-button.component.jsx +++ b/components/Buttons/create-time-ticket-button.component.jsx @@ -3,18 +3,23 @@ import { Text } from "react-native"; import { Button } from "react-native-paper"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; +import { useNavigation } from "@react-navigation/native"; + + // const mapDispatchToProps = (dispatch) => ({ // signOut: () => dispatch(employeeSignOut()), // }); -export function AddTimeTicketButton({ doOnPress }) { +export function AddTimeTicketButton() { + + const navigation = useNavigation(); const { t } = useTranslation(); return ( - - )} - - - {/* Below is for list of jobs/tickets */} - - - + + + {({ handleChange, handleBlur, handleSubmit, values }) => ( + + {/* Below will be replaced with a copy of SelectCostCenter but for jobs*/} + + + {/* Below will be replaced with a Date Picker*/} + {/* */} + + + {/* Below will set to auto fill with current employee */} + + + + {/* Below will be replaced with SelectCostCenter */} + + + + + + )} + + + {/* Below is for list of jobs/tickets */} + ); @@ -122,12 +144,9 @@ export default connect(null, null)(TimeTicketCreate); const localStyles = StyleSheet.create({ content: { display: "flex", - flex: 1 - }, - topTimeTicketContainer: { - }, - bottomTimeTicketContainer: { - }, - input: { + flex: 1, }, + topTimeTicketContainer: {}, + bottomTimeTicketContainer: {}, + input: {}, }); diff --git a/package.json b/package.json index 2b2edcc..4fc229f 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "@react-native-async-storage/async-storage": "^1.17.11", "@react-native-community/art": "^1.2.0", "@react-native-community/cli-debugger-ui": "^9.0.0", + "@react-native-community/datetimepicker": "6.7.3", "@react-native-community/masked-view": "^0.1.11", "@react-navigation/bottom-tabs": "^6.3.3", "@react-navigation/drawer": "^6.4.4", @@ -70,6 +71,7 @@ "react-native-image-gallery": "^2.1.5", "react-native-image-viewing": "^0.2.2", "react-native-indicators": "^0.17.0", + "react-native-modal-datetime-picker": "^15.0.0", "react-native-pager-view": "6.1.2", "react-native-paper": "^4.12.4", "react-native-progress": "^5.0.0", diff --git a/yarn.lock b/yarn.lock index 38c93c0..7b1b330 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2366,6 +2366,13 @@ prompts "^2.4.0" semver "^6.3.0" +"@react-native-community/datetimepicker@6.7.3": + version "6.7.3" + resolved "https://registry.yarnpkg.com/@react-native-community/datetimepicker/-/datetimepicker-6.7.3.tgz#e6d75a42729265d8404d1d668c86926564abca2f" + integrity sha512-fXWbEdHMLW/e8cts3snEsbOTbnFXfUHeO2pkiDFX3fWpFoDtUrRWvn50xbY13IJUUKHDhoJ+mj24nMRVIXfX1A== + dependencies: + invariant "^2.2.4" + "@react-native-community/masked-view@^0.1.11": version "0.1.11" resolved "https://registry.yarnpkg.com/@react-native-community/masked-view/-/masked-view-0.1.11.tgz#2f4c6e10bee0786abff4604e39a37ded6f3980ce" @@ -7986,6 +7993,13 @@ react-native-iphone-x-helper@^1.3.1: resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz#20c603e9a0e765fd6f97396638bdeb0e5a60b010" integrity sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg== +react-native-modal-datetime-picker@^15.0.0: + version "15.0.0" + resolved "https://registry.yarnpkg.com/react-native-modal-datetime-picker/-/react-native-modal-datetime-picker-15.0.0.tgz#3c2b0a63467a3391dbc202871aa2807bc1a0d8d0" + integrity sha512-cHeFEYHUhyIk+Mt9C6RVseg/VMGR4XcxdU9SibF5RMCXiXhrwMkFy7203xg1S331pzCF/Oqhvi4Jh0pYMrTFtQ== + dependencies: + prop-types "^15.7.2" + react-native-pager-view@6.1.2: version "6.1.2" resolved "https://registry.yarnpkg.com/react-native-pager-view/-/react-native-pager-view-6.1.2.tgz#3522079b9a9d6634ca5e8d153bc0b4d660254552" From 9fc2d4c67c58f9023f19e6c3e04f37a035f87c71 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 8 May 2023 17:19:59 -0400 Subject: [PATCH 031/105] Added employee name to the employee field --- .../screen-time-ticket-browser.component.jsx | 47 ++++++++++++++++++- .../screen-time-ticket-create.component.jsx | 7 +-- redux/employee/employee.sagas.js | 41 ++++++++++++++-- redux/employee/employee.selectors.js | 28 +++++++---- 4 files changed, 104 insertions(+), 19 deletions(-) diff --git a/components/screen-ap-time-ticket-list/screen-time-ticket-browser.component.jsx b/components/screen-ap-time-ticket-list/screen-time-ticket-browser.component.jsx index 94e308c..dfc966a 100644 --- a/components/screen-ap-time-ticket-list/screen-time-ticket-browser.component.jsx +++ b/components/screen-ap-time-ticket-list/screen-time-ticket-browser.component.jsx @@ -1,11 +1,54 @@ import React from "react"; import { View, Text } from "react-native"; -export default function ScreenTimeTicketBrowser() { +import { connect } from "react-redux"; +import { employeeGetRatesStart } from "../../redux/employee/employee.actions"; +import { createStructuredSelector } from "reselect"; +import { + selectCurrentEmployee, + selectRates, + selectGettingRates, + selectSignInError, +} from "../../redux/employee/employee.selectors"; +import { Button } from "react-native-paper"; + +const mapStateToProps = createStructuredSelector({ + currentEmployee: selectCurrentEmployee, + theRates: selectRates, + loaderGettingRates: selectGettingRates, + signingError: selectSignInError, +}); + +const mapDispatchToProps = (dispatch) => ({ + employeeGetRatesStart: (employeeId) => + dispatch(employeeGetRatesStart({employeeId})), +}); + +export function ScreenTimeTicketBrowser({ + loaderGettingRates, + currentEmployee, + employeeGetRatesStart, + signingError +}) { + + + const getRates = (currentEmployee) => { + employeeGetRatesStart(currentEmployee.technician.id); + }; + return ( Time Ticket List goes here - + + {signingError && signingError} ); } + +export default connect(mapStateToProps, mapDispatchToProps)(ScreenTimeTicketBrowser); \ No newline at end of file diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index 416b145..720c09f 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -16,8 +16,9 @@ import DateTimePickerModal from "react-native-modal-datetime-picker"; const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, }); +const mapDispatchToProps = (dispatch) => ({}) -export function TimeTicketCreate() { +export function TimeTicketCreate({currentEmployee}) { const [isDatePickerVisible, setDatePickerVisibility] = useState(false); const [date2, setDate2] = useState(new Date()); @@ -47,7 +48,7 @@ export function TimeTicketCreate() { initialValues={{ jobid: "", ticketdate: date2.toLocaleDateString(), - employee: "", + employee: currentEmployee.technician.first_name, costcenter: "", productivehours: "", actualhours: "", @@ -139,7 +140,7 @@ export function TimeTicketCreate() { ); } -export default connect(null, null)(TimeTicketCreate); +export default connect(mapStateToProps, null)(TimeTicketCreate); const localStyles = StyleSheet.create({ content: { diff --git a/redux/employee/employee.sagas.js b/redux/employee/employee.sagas.js index 85642fd..84c7529 100644 --- a/redux/employee/employee.sagas.js +++ b/redux/employee/employee.sagas.js @@ -3,11 +3,16 @@ import { employeeSignInStart, employeeSignInSuccess, employeeSignInFailure, + employeeGetRatesStart, + employeeGetRatesSuccess, + employeeGetRatesFailure + } from "./employee.actions"; import { all, call, put, select, takeLatest } from "redux-saga/effects"; import { logImEXEvent } from "../../firebase/firebase.analytics"; import { selectBodyshop } from "../user/user.selectors"; import axios from "axios"; +import { client } from "../../graphql/client"; export function* onSignInEmployeeStart() { yield takeLatest( @@ -17,9 +22,9 @@ export function* onSignInEmployeeStart() { } export function* signInWithEmployeeId({ payload: { employeeId, pin } }) { try { - logImEXEvent("redux_sign_in_employee_attempt"); + logImEXEvent("redux_sign_in_employee_attempt"); //console.loging - console.log("Saga", employeeId, pin, pin); + // console.log("Saga", employeeId, pin, pin); const bodyshop = yield select(selectBodyshop); const response = yield call(axios.post, "/tech/login", { shopid: bodyshop.id, @@ -38,6 +43,34 @@ export function* signInWithEmployeeId({ payload: { employeeId, pin } }) { } } -export function* employeeSagas() { - yield all([call(onSignInEmployeeStart)]); +export function* onEmployeeGetRatesStart() { + yield takeLatest( + EmployeeActionTypes.EMPLOYEE_GET_RATES_START, + getRatesWithEmployeeId + ); +} +export function* getRatesWithEmployeeId({ payload }) { + try { + const response = yield client.query({ query: QUERY_EMPLOYEE_BY_ID, + variables: { + id: payload.id, + } + }); + logImEXEvent("redux_employee_get_rates_attempt", payload); + const { valid, technician, error } = response.data; + + if (valid) { + yield put(employeeGetRatesSuccess(technician)); + } else { + yield put(employeeGetRatesFailure(error)); + } + } catch (error) { + yield put(employeeGetRatesFailure(error)); + console.log("Error while getting employee rates.", error); + Sentry.Native.captureException(error); + } +} + +export function* employeeSagas() { + yield all([call(onSignInEmployeeStart), call(employeeGetRatesSuccess)]); } diff --git a/redux/employee/employee.selectors.js b/redux/employee/employee.selectors.js index b5234a7..53e0f66 100644 --- a/redux/employee/employee.selectors.js +++ b/redux/employee/employee.selectors.js @@ -3,14 +3,22 @@ import { createSelector } from "reselect"; const selectEmployee = (state) => state.employee; export const selectCurrentEmployee = createSelector( - [selectEmployee], - (employee) => employee.currentEmployee - ); + [selectEmployee], + (employee) => employee.currentEmployee +); export const selectSigningIn = createSelector( - [selectEmployee], - (employee) => employee.signingIn - ); - export const selectSignInError = createSelector( - [selectEmployee], - (employee) => employee.error - ); \ No newline at end of file + [selectEmployee], + (employee) => employee.signingIn +); +export const selectSignInError = createSelector( + [selectEmployee], + (employee) => employee.error +); +export const selectRates = createSelector( + [selectEmployee], + (employee) => employee.currentEmployee.rates +); +export const selectGettingRates = createSelector( + [selectEmployee], + (employee) => employee.gettingRates +); From e57a3605b8811137d72673bd8618b357b924a37d Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Tue, 9 May 2023 12:27:06 -0400 Subject: [PATCH 032/105] add getemployeebyid call N costcenter dropdown --- .../create-time-ticket-button.component.jsx | 1 + components/Selects/select-cost-center.jsx | 13 ++--- .../screen-time-ticket-browser.component.jsx | 17 ++++-- .../screen-time-ticket-create.component.jsx | 47 ++++++++++------ redux/employee/employee.actions.js | 8 +-- redux/employee/employee.reducer.js | 3 +- redux/employee/employee.sagas.js | 54 +++++++++++++++---- redux/employee/employee.selectors.js | 2 +- 8 files changed, 103 insertions(+), 42 deletions(-) diff --git a/components/Buttons/create-time-ticket-button.component.jsx b/components/Buttons/create-time-ticket-button.component.jsx index df87a22..9735dc3 100644 --- a/components/Buttons/create-time-ticket-button.component.jsx +++ b/components/Buttons/create-time-ticket-button.component.jsx @@ -15,6 +15,7 @@ export function AddTimeTicketButton() { const navigation = useNavigation(); const { t } = useTranslation(); + return ( - {signingError && signingError} + {/* {signingErrorMsg} */} ); } diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index 720c09f..3b0639e 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -1,5 +1,5 @@ import { Formik } from "formik"; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { StyleSheet, Text } from "react-native"; import { useTranslation } from "react-i18next"; import { View, ScrollView } from "react-native"; @@ -9,18 +9,28 @@ import { Button, Dialog, TextInput } from "react-native-paper"; import { QUERY_EMPLOYEE_BY_ID } from "../../graphql/employees.queries"; //import SelectDropdown from 'react-native-select-dropdown'; import { SelectCostCenter } from "../Selects/select-cost-center"; -import { selectCurrentEmployee } from "../../redux/employee/employee.selectors"; +import { + selectCurrentEmployee, + selectRates, +} from "../../redux/employee/employee.selectors"; import DateTimePickerModal from "react-native-modal-datetime-picker"; //TODO add props needed for call const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, + currentRatesNCostCenters: selectRates, }); -const mapDispatchToProps = (dispatch) => ({}) +const mapDispatchToProps = (dispatch) => ({}); + +export function TimeTicketCreate({ + currentEmployee, + currentRatesNCostCenters, +}) { + const { t } = useTranslation(); -export function TimeTicketCreate({currentEmployee}) { const [isDatePickerVisible, setDatePickerVisibility] = useState(false); const [date2, setDate2] = useState(new Date()); + const [costCenters, setCostCenters] = useState([]); const showDatePicker = () => { setDatePickerVisibility(true); @@ -33,14 +43,23 @@ export function TimeTicketCreate({currentEmployee}) { //console.warn("A date has been picked: ", date); hideDatePicker(); }; - - const { t } = useTranslation(); - const formSubmit = (values) => { Dialog.alert({ content:
{JSON.stringify(values, null, 2)}
}); //TODO update with start call for create time ticket }; + useEffect(() => { + var count = Object.keys(currentRatesNCostCenters).length; + let selectDataArray = []; + for (let i = 0; i < count; i++) { + selectDataArray.push({ + value: currentRatesNCostCenters[i].cost_center, + label: currentRatesNCostCenters[i].cost_center, + }); + } + setCostCenters(selectDataArray); + }, []); + return ( @@ -68,16 +87,10 @@ export function TimeTicketCreate({currentEmployee}) { /> {/* Below will be replaced with a Date Picker*/} - {/* */} + {/* */} - + {/* Below will be replaced with SelectCostCenter */} ({ type: EmployeeActionTypes.EMPLOYEE_SIGN_OUT, }); -export const employeeGetRatesStart = (id) => ({ +export const employeeGetRatesStart = (employeeId) => ({ type: EmployeeActionTypes.EMPLOYEE_GET_RATES_START, - payload: id, + payload: employeeId, }); -export const employeeGetRatesSuccess = (technician) => ({ +export const employeeGetRatesSuccess = (employees_by_pk) => ({ type: EmployeeActionTypes.EMPLOYEE_GET_RATES_SUCCESS, - payload: technician, + payload: employees_by_pk, }); export const employeeGetRatesFailure = (error) => ({ type: EmployeeActionTypes.EMPLOYEE_GET_RATES_FAILURE, diff --git a/redux/employee/employee.reducer.js b/redux/employee/employee.reducer.js index 457066a..a48b881 100644 --- a/redux/employee/employee.reducer.js +++ b/redux/employee/employee.reducer.js @@ -46,8 +46,7 @@ const employeeReducer = (state = INITIAL_STATE, action) => { case EmployeeActionTypes.EMPLOYEE_GET_RATES_SUCCESS: return { ...state, - //currentEmployee: { authorized: true, technician:action.payload }, - currentEmployee: { rates:action.payload },//TODO check if ...state needed + currentEmployee: { ...state.currentEmployee, technician:action.payload }, gettingRates: false, error: null, }; diff --git a/redux/employee/employee.sagas.js b/redux/employee/employee.sagas.js index 84c7529..34ddfe6 100644 --- a/redux/employee/employee.sagas.js +++ b/redux/employee/employee.sagas.js @@ -13,6 +13,8 @@ import { logImEXEvent } from "../../firebase/firebase.analytics"; import { selectBodyshop } from "../user/user.selectors"; import axios from "axios"; import { client } from "../../graphql/client"; +import { QUERY_EMPLOYEE_BY_ID } from "../../graphql/employees.queries"; +import { selectCurrentEmployee } from "./employee.selectors"; export function* onSignInEmployeeStart() { yield takeLatest( @@ -43,34 +45,68 @@ export function* signInWithEmployeeId({ payload: { employeeId, pin } }) { } } +/* +//Waits for EMPLOYEE_SIGN_IN_SUCCESS when logging in to then call QUERY_EMPLOYEE_BY_ID with the id in payload to override technician with more data like rates and flat_rate +*/ +export function* onEmployeeSignInSuccessSaga() { + yield takeLatest( + EmployeeActionTypes.EMPLOYEE_SIGN_IN_SUCCESS, + updateEmployeeWithEmployeeId + ); +} +export function* updateEmployeeWithEmployeeId({ payload }) { + try { + const employeeId = payload.id; + // logImEXEvent("redux_update_employee_with_employee_id_attempt", employeeId); + const result = yield client.query({ query: QUERY_EMPLOYEE_BY_ID, + variables: { + id: employeeId, + } + }); + const { employees_by_pk } = result.data; + if (employees_by_pk) { + yield put(employeeGetRatesSuccess(employees_by_pk)); + } else { + yield put(employeeGetRatesFailure(result.error)); + } + } catch (error) { + yield put(employeeGetRatesFailure(error)); + console.log("Error while getting employee rates.", error); + //Sentry.Native.captureException(error); + } +} + + + export function* onEmployeeGetRatesStart() { yield takeLatest( EmployeeActionTypes.EMPLOYEE_GET_RATES_START, getRatesWithEmployeeId ); } -export function* getRatesWithEmployeeId({ payload }) { +export function* getRatesWithEmployeeId({ payload: employeeId }) { try { - const response = yield client.query({ query: QUERY_EMPLOYEE_BY_ID, + + logImEXEvent("redux_employee_get_rates_attempt", employeeId); + const result = yield client.query({ query: QUERY_EMPLOYEE_BY_ID, variables: { - id: payload.id, + id: employeeId, } }); - logImEXEvent("redux_employee_get_rates_attempt", payload); - const { valid, technician, error } = response.data; + const { employees_by_pk } = result.data; - if (valid) { - yield put(employeeGetRatesSuccess(technician)); + if (employees_by_pk) { + yield put(employeeGetRatesSuccess(employees_by_pk)); } else { yield put(employeeGetRatesFailure(error)); } } catch (error) { yield put(employeeGetRatesFailure(error)); console.log("Error while getting employee rates.", error); - Sentry.Native.captureException(error); + //Sentry.Native.captureException(error); } } export function* employeeSagas() { - yield all([call(onSignInEmployeeStart), call(employeeGetRatesSuccess)]); + yield all([call(onSignInEmployeeStart), call(onEmployeeSignInSuccessSaga), call(onEmployeeGetRatesStart)]); } diff --git a/redux/employee/employee.selectors.js b/redux/employee/employee.selectors.js index 53e0f66..a611301 100644 --- a/redux/employee/employee.selectors.js +++ b/redux/employee/employee.selectors.js @@ -16,7 +16,7 @@ export const selectSignInError = createSelector( ); export const selectRates = createSelector( [selectEmployee], - (employee) => employee.currentEmployee.rates + (employee) => employee.currentEmployee.technician.rates ); export const selectGettingRates = createSelector( [selectEmployee], From c8ef54b153e99d22cb5e5077f200eee179494681 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Tue, 9 May 2023 14:01:20 -0400 Subject: [PATCH 033/105] added tt_allow_post_to_invoiced to QUERY_BODYSHOP --- graphql/bodyshop.queries.js | 1 + 1 file changed, 1 insertion(+) diff --git a/graphql/bodyshop.queries.js b/graphql/bodyshop.queries.js index eaf877f..3f2d6be 100644 --- a/graphql/bodyshop.queries.js +++ b/graphql/bodyshop.queries.js @@ -11,6 +11,7 @@ export const QUERY_BODYSHOP = gql` shopname features localmediatoken + tt_allow_post_to_invoiced } } `; From 8404873d402230c23b408228ea8589ca854ef3ad Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Tue, 9 May 2023 14:03:06 -0400 Subject: [PATCH 034/105] add SEARCH_JOBS_FOR_AUTOCOMPLETE N S_JS_BY_ID_F_A --- graphql/jobs.queries.js | 48 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/graphql/jobs.queries.js b/graphql/jobs.queries.js index bd4b017..d56fa26 100644 --- a/graphql/jobs.queries.js +++ b/graphql/jobs.queries.js @@ -451,6 +451,54 @@ export const ACTIVE_JOBS_FOR_AUTOCOMPLETE = gql` } `; +export const SEARCH_JOBS_FOR_AUTOCOMPLETE = gql` + query SEARCH_JOBS_FOR_AUTOCOMPLETE( + $search: String + $isConverted: Boolean + $notExported: Boolean + $notInvoiced: Boolean + ) { + search_jobs( + args: { search: $search } + limit: 50 + where: { + _and: { + converted: { _eq: $isConverted } + date_exported: { _is_null: $notExported } + date_invoiced: { _is_null: $notInvoiced } + } + } + ) { + id + ownr_fn + ownr_ln + ro_number + clm_no + vehicleid + v_make_desc + v_model_desc + v_model_yr + status + } + } +`; +export const SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE = gql` + query SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE($id: uuid!) { + jobs_by_pk(id: $id) { + id + ownr_fn + ownr_ln + ro_number + clm_no + vehicleid + v_make_desc + v_model_desc + v_model_yr + status + } + } +`; + export const SEARCH_FOR_JOBS = gql` query SEARCH_FOR_JOBS($search: String!) { jobs(where: { ro_number: { _ilike: $search } }) { From c4705085056dec1f346c0ab1d8fc8e0d957c2180 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Tue, 9 May 2023 16:19:34 -0400 Subject: [PATCH 035/105] added select job id selector --- components/Selects/select-cost-center.jsx | 7 - components/Selects/select-job-name.jsx | 165 ++++++++++++++++++ .../owner-name-display.component.jsx | 47 +++++ .../screen-time-ticket-create.component.jsx | 61 ++++--- 4 files changed, 247 insertions(+), 33 deletions(-) create mode 100644 components/Selects/select-job-name.jsx create mode 100644 components/owner-name-display/owner-name-display.component.jsx diff --git a/components/Selects/select-cost-center.jsx b/components/Selects/select-cost-center.jsx index 51c59fa..d11d82e 100644 --- a/components/Selects/select-cost-center.jsx +++ b/components/Selects/select-cost-center.jsx @@ -5,7 +5,6 @@ import { Dropdown } from "react-native-element-dropdown"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; -//TODO Justin currently inprogress import { selectCurrentTimeTicketJob, selectCurrentTimeTicketJobId, @@ -17,11 +16,6 @@ const data = [ { label: "Item 1", value: "1" }, { label: "Item 2", value: "3" }, { label: "Item 3", value: "3" }, - { label: "Item 4", value: "4" }, - { label: "Item 5", value: "5" }, - { label: "Item 6", value: "6" }, - { label: "Item 7", value: "7" }, - { label: "Item 8", value: "8" }, ]; // const mapStateToProps = createStructuredSelector({ @@ -78,7 +72,6 @@ export default connect(null, null)(SelectCostCenter); const styles = StyleSheet.create({ container: { - backgroundColor: "white", padding: 16, justifyContent: "center", alignContent: "center", diff --git a/components/Selects/select-job-name.jsx b/components/Selects/select-job-name.jsx new file mode 100644 index 0000000..6b0655b --- /dev/null +++ b/components/Selects/select-job-name.jsx @@ -0,0 +1,165 @@ +import { useLazyQuery } from "@apollo/client"; +import React, { forwardRef, useState, useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import _ from "lodash"; + +import { + SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE, + SEARCH_JOBS_FOR_AUTOCOMPLETE, +} from "../../graphql/jobs.queries"; +import { StyleSheet, Text, View } from "react-native"; +import { Dropdown } from "react-native-element-dropdown"; +import { connect } from "react-redux"; +import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component"; + +export function JobSearchSelect( + convertedOnly = false, + notInvoiced = false, + notExported = true, + clm_no = false, + ...restProps +) { + const { t } = useTranslation(); + const [selectorData, setSelectorData] = useState([]); + const [selectedvalue, setSelectedValue] = useState(null); + const [isFocus, setIsFocus] = useState(false); + + const [theOptions, setTheOptions] = useState([]); + + const [callSearch, { loading, error, data }] = useLazyQuery( + SEARCH_JOBS_FOR_AUTOCOMPLETE, + {} + ); + const [callIdSearch, { loading: idLoading, error: idError, data: idData }] = + useLazyQuery(SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE); + + const executeSearch = (v) => { + if (v && v !== "") callSearch(v); + }; + const debouncedExecuteSearch = _.debounce(executeSearch, 500); + + const handleSearch = (value) => { + debouncedExecuteSearch({ + variables: { + search: value, + ...(convertedOnly || notExported + ? { + ...(convertedOnly ? { isConverted: true } : {}), + ...(notExported ? { notExported: true } : {}), + ...(notInvoiced ? { notInvoiced: true } : {}), + } + : {}), + }, + }); + }; + + useEffect(() => { + if (restProps.value) { + callIdSearch({ variables: { id: restProps.value } }); + } + }, [restProps.value, callIdSearch]); + + useEffect(() => { + setTheOptions( + _.uniqBy( + [ + ...(idData && idData.jobs_by_pk ? [idData.jobs_by_pk] : []), + ...(data && data.search_jobs ? data.search_jobs : []), + ], + "id" + ) + ); + }, [data, idData]); + + useEffect(() => { + var count = Object.keys(theOptions).length; + 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 || "" + // }`, + + }); + } + setSelectorData(selectDataArray); + }, [theOptions]); + return ( + + setIsFocus(true)} + onBlur={() => setIsFocus(false)} + onChange={(item) => { + console.log(item); + setSelectedValue(item.value); + setIsFocus(false); + }} + onChangeText={(search) => { + handleSearch(search); + }} + /> + {/* {theOptions ? console.log(theOptions): null} */} + + ); +} + +export default connect(null, null)(JobSearchSelect); + +const styles = StyleSheet.create({ + container: { + padding: 16, + justifyContent: "center", + alignContent: "center", + }, + dropdown: { + height: 50, + borderColor: "gray", + borderWidth: 0.5, + borderRadius: 8, + paddingHorizontal: 8, + }, + icon: { + marginRight: 5, + }, + label: { + position: "absolute", + backgroundColor: "white", + left: 22, + top: 8, + zIndex: 999, + paddingHorizontal: 8, + fontSize: 14, + }, + placeholderStyle: { + fontSize: 16, + }, + selectedTextStyle: { + fontSize: 16, + }, + iconStyle: { + width: 20, + height: 20, + }, + inputSearchStyle: { + height: 40, + fontSize: 16, + }, +}); diff --git a/components/owner-name-display/owner-name-display.component.jsx b/components/owner-name-display/owner-name-display.component.jsx new file mode 100644 index 0000000..da79657 --- /dev/null +++ b/components/owner-name-display/owner-name-display.component.jsx @@ -0,0 +1,47 @@ +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { store } from "../../redux/store"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +const mapStateToProps = createStructuredSelector({ + bodyshop: selectBodyshop, +}); +const mapDispatchToProps = (dispatch) => ({ + //setUserLanguage: language => dispatch(setUserLanguage(language)) +}); +export default connect(mapStateToProps, mapDispatchToProps)(OwnerNameDisplay); + +export function OwnerNameDisplay({ bodyshop, ownerObject }) { + const emptyTest = + ownerObject?.ownr_fn + ownerObject?.ownr_ln + ownerObject?.ownr_co_nm; + + if (!emptyTest || emptyTest === "null" || emptyTest.trim() === "") + return "N/A"; + + if (bodyshop.last_name_first) + return `${ownerObject?.ownr_ln || ""}, ${ownerObject?.ownr_fn || ""} ${ + ownerObject?.ownr_co_nm || "" + }`.trim(); + + return `${ownerObject?.ownr_fn || ""} ${ownerObject?.ownr_ln || ""} ${ + ownerObject.ownr_co_nm || "" + }`.trim(); +} + +export function OwnerNameDisplayFunction(ownerObject, forceFirstLast = false) { + const emptyTest = + ownerObject?.ownr_fn + ownerObject?.ownr_ln + ownerObject?.ownr_co_nm; + + if (!emptyTest || emptyTest === "null" || emptyTest.trim() === "") + return "N/A"; + + const rdxStore = store.getState(); + + if (rdxStore.user.bodyshop.last_name_first && !forceFirstLast) + return `${ownerObject?.ownr_ln || ""}, ${ownerObject?.ownr_fn || ""} ${ + ownerObject?.ownr_co_nm || "" + }`.trim(); + + return `${ownerObject?.ownr_fn || ""} ${ownerObject?.ownr_ln || ""} ${ + ownerObject?.ownr_co_nm || "" + }`.trim(); +} diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index 3b0639e..e2c8258 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -14,17 +14,21 @@ import { selectRates, } from "../../redux/employee/employee.selectors"; import DateTimePickerModal from "react-native-modal-datetime-picker"; +import { JobSearchSelect } from "../Selects/select-job-name"; +import { selectBodyshop } from "../../redux/user/user.selectors"; //TODO add props needed for call const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, currentRatesNCostCenters: selectRates, + bodyshop: selectBodyshop, }); const mapDispatchToProps = (dispatch) => ({}); export function TimeTicketCreate({ currentEmployee, currentRatesNCostCenters, + bodyshop }) { const { t } = useTranslation(); @@ -77,20 +81,13 @@ 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*/} {/* */} - {/* Below will set to auto fill with current employee */} - {/* Below will be replaced with SelectCostCenter */} + - Date: Wed, 10 May 2023 15:43:40 -0400 Subject: [PATCH 036/105] added timeticket redux --- .../screen-time-ticket-create.component.jsx | 39 +++++++------- graphql/bodyshop.queries.js | 1 + redux/app/app.reducer.js | 12 ----- redux/app/app.types.js | 2 - redux/employee/employee.actions.js | 13 +---- redux/employee/employee.reducer.js | 1 - redux/employee/employee.types.js | 3 -- redux/root.reducer.js | 2 + redux/root.saga.js | 3 +- redux/timetickets/timetickets.actions.js | 25 +++++++++ redux/timetickets/timetickets.reducer.js | 51 +++++++++++++++++++ redux/timetickets/timetickets.sagas.js | 51 +++++++++++++++++++ redux/timetickets/timetickets.selectors.js | 16 ++++++ redux/timetickets/timetickets.types.js | 9 ++++ 14 files changed, 177 insertions(+), 51 deletions(-) create mode 100644 redux/timetickets/timetickets.actions.js create mode 100644 redux/timetickets/timetickets.reducer.js create mode 100644 redux/timetickets/timetickets.sagas.js create mode 100644 redux/timetickets/timetickets.selectors.js create mode 100644 redux/timetickets/timetickets.types.js diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index e2c8258..a9ca0e4 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -1,34 +1,31 @@ import { Formik } from "formik"; import React, { useEffect, useState } from "react"; -import { StyleSheet, Text } from "react-native"; +import { StyleSheet, Text,View, ScrollView } from "react-native"; import { useTranslation } from "react-i18next"; -import { View, ScrollView } from "react-native"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { Button, Dialog, TextInput } from "react-native-paper"; -import { QUERY_EMPLOYEE_BY_ID } from "../../graphql/employees.queries"; -//import SelectDropdown from 'react-native-select-dropdown'; import { SelectCostCenter } from "../Selects/select-cost-center"; +import { JobSearchSelect } from "../Selects/select-job-name"; +import DateTimePickerModal from "react-native-modal-datetime-picker"; import { selectCurrentEmployee, selectRates, } from "../../redux/employee/employee.selectors"; -import DateTimePickerModal from "react-native-modal-datetime-picker"; -import { JobSearchSelect } from "../Selects/select-job-name"; import { selectBodyshop } from "../../redux/user/user.selectors"; //TODO add props needed for call const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, currentRatesNCostCenters: selectRates, - bodyshop: selectBodyshop, + currentBodyshop: selectBodyshop, }); -const mapDispatchToProps = (dispatch) => ({}); +// const mapDispatchToProps = (dispatch) => ({}); export function TimeTicketCreate({ currentEmployee, currentRatesNCostCenters, - bodyshop + currentBodyshop }) { const { t } = useTranslation(); @@ -53,15 +50,17 @@ export function TimeTicketCreate({ }; useEffect(() => { - var count = Object.keys(currentRatesNCostCenters).length; - let selectDataArray = []; - for (let i = 0; i < count; i++) { - selectDataArray.push({ - value: currentRatesNCostCenters[i].cost_center, - label: currentRatesNCostCenters[i].cost_center, - }); - } - setCostCenters(selectDataArray); + if (typeof currentRatesNCostCenters !== 'undefined') { + var count = Object.keys(currentRatesNCostCenters).length; + let selectDataArray = []; + for (let i = 0; i < count; i++) { + selectDataArray.push({ + value: currentRatesNCostCenters[i].cost_center, + label: currentRatesNCostCenters[i].cost_center, + }); + } + setCostCenters(selectDataArray); + } }, []); return ( @@ -81,8 +80,8 @@ 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*/} {/* */} diff --git a/graphql/bodyshop.queries.js b/graphql/bodyshop.queries.js index 3f2d6be..374dc3e 100644 --- a/graphql/bodyshop.queries.js +++ b/graphql/bodyshop.queries.js @@ -1,5 +1,6 @@ import gql from "graphql-tag"; +//TODO: find out if cdk_dealerid, pbs_serialnumber and md_responsibility_centers.defaults.costs need to be added to this export const QUERY_BODYSHOP = gql` query QUERY_BODYSHOP { bodyshops(where: { associations: { active: { _eq: true } } }) { diff --git a/redux/app/app.reducer.js b/redux/app/app.reducer.js index b99b3f8..aa15d0c 100644 --- a/redux/app/app.reducer.js +++ b/redux/app/app.reducer.js @@ -6,8 +6,6 @@ const INITIAL_STATE = { documentUploadInProgress: null, documentUploadError: null, deleteAfterUpload: false, - timeTicketJobId: null, - timeTicketJob: null, }; const appReducer = (state = INITIAL_STATE, action) => { @@ -45,16 +43,6 @@ const appReducer = (state = INITIAL_STATE, action) => { ...state, deleteAfterUpload: !state.deleteAfterUpload, }; - case AppActionTypes.SET_TIME_TICKET_JOB_ID: - return { - ...state, - timeTicketJobId: action.payload, - }; - case AppActionTypes.SET_TIME_TICKET_JOB: - return { - ...state, - timeTicketJob: action.payload, - }; default: return state; } diff --git a/redux/app/app.types.js b/redux/app/app.types.js index 2f36bfb..029d8e0 100644 --- a/redux/app/app.types.js +++ b/redux/app/app.types.js @@ -5,7 +5,5 @@ const AppActionTypes = { DOCUMENT_UPLOAD_SUCCESS: "DOCUMENT_UPLOAD_SUCCESS", DOCUMENT_UPLOAD_FAILURE: "DOCUMENT_UPLOAD_FAILURE", TOGGLE_DLETE_AFTER_UPLOAD: "TOGGLE_DLETE_AFTER_UPLOAD", - SET_TIME_TICKET_JOB: "SET_TIME_TICKET_JOB", - SET_TIME_TICKET_JOB_ID: "SET_TIME_TICKET_JOB_ID", }; export default AppActionTypes; diff --git a/redux/employee/employee.actions.js b/redux/employee/employee.actions.js index e5c3f77..4de1cde 100644 --- a/redux/employee/employee.actions.js +++ b/redux/employee/employee.actions.js @@ -31,15 +31,4 @@ export const employeeGetRatesFailure = (error) => ({ type: EmployeeActionTypes.EMPLOYEE_GET_RATES_FAILURE, payload: error, }); -export const timeTicketCreateStart = (timeTicket) => ({ - type: EmployeeActionTypes.TIME_TICKET_CREATE_START, - payload: timeTicket, -}); -export const timeTicketCreateSuccess = (insertTimeTickets) => ({ - type: EmployeeActionTypes.TIME_TICKET_CREATE_SUCCESS, - payload: insertTimeTickets, -}); -export const timeTicketCreateFailure = (error) => ({ - type: EmployeeActionTypes.TIME_TICKET_CREATE_FAILURE, - payload: error, -}); + diff --git a/redux/employee/employee.reducer.js b/redux/employee/employee.reducer.js index a48b881..cbb73bd 100644 --- a/redux/employee/employee.reducer.js +++ b/redux/employee/employee.reducer.js @@ -4,7 +4,6 @@ const INITIAL_STATE = { currentEmployee: { authorized: null, technician: null, - rates:[], }, signingIn: false, gettingRates: false, diff --git a/redux/employee/employee.types.js b/redux/employee/employee.types.js index 6bdf9fc..44fd208 100644 --- a/redux/employee/employee.types.js +++ b/redux/employee/employee.types.js @@ -6,9 +6,6 @@ const EmployeeActionTypes = { EMPLOYEE_AUTHORIZING_SUCCESS: "EMPLOYEE_AUTHORIZING_SUCCESS", EMPLOYEE_AUTHORIZING_FAILURE: "EMPLOYEE_AUTHORIZING_FAILURE", EMPLOYEE_SIGN_OUT: "EMPLOYEE_SIGN_OUT", - TIME_TICKET_CREATE_START: "TIME_TICKET_CREATE_START", - TIME_TICKET_CREATE_SUCCESS: "TIME_TICKET_CREATE_SUCCESS", - TIME_TICKET_CREATE_FAILURE: "TIME_TICKET_CREATE_FAILURE", EMPLOYEE_GET_RATES_START: "EMPLOYEE_GET_RATES_START", EMPLOYEE_GET_RATES_SUCCESS: "EMPLOYEE_GET_RATES_SUCCESS", EMPLOYEE_GET_RATES_FAILURE: "EMPLOYEE_GET_RATES_FAILURE", diff --git a/redux/root.reducer.js b/redux/root.reducer.js index 963952f..1ace819 100644 --- a/redux/root.reducer.js +++ b/redux/root.reducer.js @@ -5,6 +5,7 @@ import appReducer from "./app/app.reducer"; import photosReducer from "./photos/photos.reducer"; import userReducer from "./user/user.reducer"; import employeeReducer from './employee/employee.reducer'; +import timeTicketsReducer from './timetickets/timetickets.reducer'; const persistConfig = { key: "root", @@ -18,6 +19,7 @@ const rootReducer = combineReducers({ app: appReducer, photos: photosReducer, employee: employeeReducer, + timeTickets: timeTicketsReducer, }); export default persistReducer(persistConfig, rootReducer); diff --git a/redux/root.saga.js b/redux/root.saga.js index c217084..8f41c44 100644 --- a/redux/root.saga.js +++ b/redux/root.saga.js @@ -3,7 +3,8 @@ import { appSagas } from "./app/app.sagas"; import { photosSagas } from "./photos/photos.sagas"; import { userSagas } from "./user/user.sagas"; 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)]); + 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 new file mode 100644 index 0000000..57c1c46 --- /dev/null +++ b/redux/timetickets/timetickets.actions.js @@ -0,0 +1,25 @@ +import TimeTicketsActionTypes from "./timetickets.types"; +export const setTimeTicket = (timeTicket) => ({ + type: TimeTicketsActionTypes.SET_TIME_TICKET, + payload: timeTicket, + }); +export const setTimeTicketJobId = (jobId) => ({ + type: TimeTicketsActionTypes.SET_TIME_TICKET_JOB_ID, + payload: jobId, +}); +export const setTimeTicketJob = (job) => ({ + type: TimeTicketsActionTypes.SET_TIME_TICKET_JOB, + payload: job, +}); +export const timeTicketCreateStart = (timeTicket) => ({ + type: TimeTicketsActionTypes.TIME_TICKET_CREATE_START, + payload: timeTicket, +}); +export const timeTicketCreateSuccess = (insertTimeTickets) => ({ + type: TimeTicketsActionTypes.TIME_TICKET_CREATE_SUCCESS, + payload: insertTimeTickets, +}); +export const timeTicketCreateFailure = (error) => ({ + type: TimeTicketsActionTypes.TIME_TICKET_CREATE_FAILURE, + payload: error, +}); diff --git a/redux/timetickets/timetickets.reducer.js b/redux/timetickets/timetickets.reducer.js new file mode 100644 index 0000000..d63bf7a --- /dev/null +++ b/redux/timetickets/timetickets.reducer.js @@ -0,0 +1,51 @@ +import TimeTicketsActionTypes from "./timetickets.types"; + +const INITIAL_STATE = { + timeTicket: null, + timeTickets: [], + timeTicketJobId: null, + timeTicketJob: null, + uploadTimeTicketInProgress: false, + uploadTimeTicketError: null, +}; + +const timeTicketsReducer = (state = INITIAL_STATE, action) => { + switch (action.type) { + case TimeTicketsActionTypes.SET_TIME_TICKET: + return { + ...state, + timeTicket: action.payload, + }; + case TimeTicketsActionTypes.SET_TIME_TICKET_JOB_ID: + return { + ...state, + timeTicketJobId: action.payload, + }; + case TimeTicketsActionTypes.SET_TIME_TICKET_JOB: + return { + ...state, + timeTicketJob: action.payload, + }; + case TimeTicketsActionTypes.TIME_TICKET_CREATE_START: + return { + ...state, + uploadTimeTicketInProgress: true, + }; + case TimeTicketsActionTypes.TIME_TICKET_CREATE_SUCCESS: + return { + ...state, //TODO add logic here when successful + uploadTimeTicketInProgress: false, + uploadTimeTicketError: null, + }; + case TimeTicketsActionTypes.TIME_TICKET_CREATE_FAILURE: + return { + ...state, + uploadTimeTicketInProgress: false, + uploadTimeTicketError: action.payload, + }; + default: + return state; + } +}; + +export default timeTicketsReducer; diff --git a/redux/timetickets/timetickets.sagas.js b/redux/timetickets/timetickets.sagas.js new file mode 100644 index 0000000..c7d2ec1 --- /dev/null +++ b/redux/timetickets/timetickets.sagas.js @@ -0,0 +1,51 @@ +import { + timeTicketCreateFailure, + timeTicketCreateSuccess, +} from "./timetickets.actions"; +import TimeTicketsActionTypes from "./timetickets.types"; +import { client } from "../../graphql/client"; + +import { all, call, put, select, takeLatest } from "redux-saga/effects"; +import { logImEXEvent } from "../../firebase/firebase.analytics"; +import { selectCurrentTimeTicket } from "./timetickets.selectors"; +import { INSERT_NEW_TIME_TICKET } from "../../graphql/timetickets.queries"; + + +export function* onCreateTimeTicketStart() { + yield takeLatest( + TimeTicketsActionTypes.TIME_TICKET_CREATE_START, + insertNewTimeTicket + ); +} +export function* insertNewTimeTicket({ payload: { timeticketinsert } }) { + try { + logImEXEvent("redux_insertnewtimeticket_attempt"); + //console.loging + // console.log("Saga", employeeId, pin, pin); + const timeTicket = yield select(selectCurrentTimeTicket); + // const response = yield call(axios.post, "/tech/login", { + // shopid: bodyshop.id, + // employeeid: employeeId, + // pin: pin, + // }); + // const { valid, data, error } = response.data; + const result = yield client.query({ + query: INSERT_NEW_TIME_TICKET, + variables: { + id: employeeId, + }, + }); + const { valid, data, error } = result.data; + if (valid) { + yield put(timeTicketCreateSuccess(data)); + } else { + yield put(timeTicketCreateFailure(error)); + } + } catch (error) { + yield put(timeTicketCreateFailure(error)); + } +} + +export function* timeTicketsSagas() { + yield all([call(onCreateTimeTicketStart)]); +} diff --git a/redux/timetickets/timetickets.selectors.js b/redux/timetickets/timetickets.selectors.js new file mode 100644 index 0000000..2539e99 --- /dev/null +++ b/redux/timetickets/timetickets.selectors.js @@ -0,0 +1,16 @@ +import { createSelector } from "reselect"; + +const selectTimeTicketsState = (state) => state.TimeTickets; + +export const selectCurrentTimeTicketJobId = createSelector( + [selectTimeTicketsState], + (TimeTickets) => TimeTickets.timeTicketJobId +); +export const selectCurrentTimeTicketJob = createSelector( + [selectTimeTicketsState], + (TimeTickets) => TimeTickets.timeTicketJob +); +export const selectCurrentTimeTicket = createSelector( + [selectTimeTicketsState], + (TimeTickets) => TimeTickets.timeTicket +); diff --git a/redux/timetickets/timetickets.types.js b/redux/timetickets/timetickets.types.js new file mode 100644 index 0000000..5737385 --- /dev/null +++ b/redux/timetickets/timetickets.types.js @@ -0,0 +1,9 @@ +const TimeTicketsActionTypes = { + SET_TIME_TICKET: "SET_TIME_TICKET", + SET_TIME_TICKET_JOB: "SET_TIME_TICKET_JOB", + SET_TIME_TICKET_JOB_ID: "SET_TIME_TICKET_JOB_ID", + TIME_TICKET_CREATE_START: "TIME_TICKET_CREATE_START", + TIME_TICKET_CREATE_SUCCESS: "TIME_TICKET_CREATE_SUCCESS", + TIME_TICKET_CREATE_FAILURE: "TIME_TICKET_CREATE_FAILURE", +}; +export default TimeTicketsActionTypes; From d311e4a029b1c0e643344ad4cabad2726f948bea Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 11 May 2023 09:29:56 -0400 Subject: [PATCH 037/105] updated naming of screen timeticket browser --- .../screen-time-ticket-browser.component.jsx | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename components/{screen-ap-time-ticket-list => screen-time-ticket-browser}/screen-time-ticket-browser.component.jsx (100%) diff --git a/components/screen-ap-time-ticket-list/screen-time-ticket-browser.component.jsx b/components/screen-time-ticket-browser/screen-time-ticket-browser.component.jsx similarity index 100% rename from components/screen-ap-time-ticket-list/screen-time-ticket-browser.component.jsx rename to components/screen-time-ticket-browser/screen-time-ticket-browser.component.jsx From f194ac242433102e0f1dd34e20bd3e60b7d436fe Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 11 May 2023 10:14:12 -0400 Subject: [PATCH 038/105] adding properties to QUERY_BODYSHOP --- graphql/bodyshop.queries.js | 3 +++ redux/timetickets/timetickets.sagas.js | 24 ++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/graphql/bodyshop.queries.js b/graphql/bodyshop.queries.js index 374dc3e..b7a336b 100644 --- a/graphql/bodyshop.queries.js +++ b/graphql/bodyshop.queries.js @@ -6,6 +6,8 @@ export const QUERY_BODYSHOP = gql` bodyshops(where: { associations: { active: { _eq: true } } }) { id jobsizelimit + cdk_dealerid + pbs_serialnumber md_ro_statuses uselocalmediaserver localmediaserverhttp @@ -13,6 +15,7 @@ export const QUERY_BODYSHOP = gql` features localmediatoken tt_allow_post_to_invoiced + md_responsibility_centers } } `; diff --git a/redux/timetickets/timetickets.sagas.js b/redux/timetickets/timetickets.sagas.js index c7d2ec1..7e876b3 100644 --- a/redux/timetickets/timetickets.sagas.js +++ b/redux/timetickets/timetickets.sagas.js @@ -17,7 +17,7 @@ export function* onCreateTimeTicketStart() { insertNewTimeTicket ); } -export function* insertNewTimeTicket({ payload: { timeticketinsert } }) { +export function* insertNewTimeTicket({ payload: { timeTicketInput } }) { try { logImEXEvent("redux_insertnewtimeticket_attempt"); //console.loging @@ -32,7 +32,27 @@ export function* insertNewTimeTicket({ payload: { timeticketinsert } }) { const result = yield client.query({ query: INSERT_NEW_TIME_TICKET, variables: { - id: employeeId, + 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 + ); + }), + }, + ], }, }); const { valid, data, error } = result.data; From 1f8575140497eb2382f32d3ccb2e8fc578a186cf Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 11 May 2023 15:09:56 -0400 Subject: [PATCH 039/105] updated costcenterselector --- components/Selects/select-cost-center.jsx | 45 +++++----- .../screen-time-ticket-browser.component.jsx | 89 +++++++++++++++---- .../screen-time-ticket-create.component.jsx | 22 +---- 3 files changed, 103 insertions(+), 53 deletions(-) diff --git a/components/Selects/select-cost-center.jsx b/components/Selects/select-cost-center.jsx index d11d82e..1925d85 100644 --- a/components/Selects/select-cost-center.jsx +++ b/components/Selects/select-cost-center.jsx @@ -5,12 +5,9 @@ import { Dropdown } from "react-native-element-dropdown"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; -import { - selectCurrentTimeTicketJob, - selectCurrentTimeTicketJobId, - } from "../../redux/app/app.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; import { QUERY_EMPLOYEE_BY_ID } from "../../graphql/employees.queries"; +import { useEffect } from "react"; const data = [ { label: "Item 1", value: "1" }, @@ -26,20 +23,27 @@ const data = [ // const mapDispatchToProps = {}; -export function SelectCostCenter(props) { +export function CostCenterSelect(props) { + const currentRatesNCostCenters = props.currentRatesNCostCenters; + const [value, setValue] = useState(null); + const [isFocus, setIsFocus] = useState(false); + const [costCenters, setCostCenters] = useState([]); - const [selectorData, setSelectorData] = useState([]); - const [value, setValue] = useState(null); - const [isFocus, setIsFocus] = useState(false); - - -// const { loading, error, data } = useQuery(QUERY_EMPLOYEE_BY_ID, { -// variables: { id: technician.id,}, -// fetchPolicy: "network-only", -// nextFetchPolicy: "network-only", -// } -// ); + useEffect(() => { + if (typeof currentRatesNCostCenters !== "undefined") { + var count = Object.keys(currentRatesNCostCenters).length; + let selectDataArray = []; + for (let i = 0; i < count; i++) { + selectDataArray.push({ + value: currentRatesNCostCenters[i].cost_center, + label: currentRatesNCostCenters[i].cost_center, + rate: currentRatesNCostCenters[i].rate, + }); + } + setCostCenters(selectDataArray); + } + }, [currentRatesNCostCenters]); return ( @@ -49,18 +53,19 @@ export function SelectCostCenter(props) { selectedTextStyle={styles.selectedTextStyle} inputSearchStyle={styles.inputSearchStyle} iconStyle={styles.iconStyle} - data={props.selectorData} + data={costCenters} search maxHeight={300} labelField="label" valueField="value" placeholder={!isFocus ? "Select Cost Center" : "..."} searchPlaceholder="Search..." - value={value} + value={props.currentValue?.value} onFocus={() => setIsFocus(true)} onBlur={() => setIsFocus(false)} onChange={(item) => { - setValue(item.value); + props.onValueSelected(item); + //setValue(item.value); setIsFocus(false); }} /> @@ -68,7 +73,7 @@ export function SelectCostCenter(props) { ); } -export default connect(null, null)(SelectCostCenter); +export default connect(null, null)(CostCenterSelect); const styles = StyleSheet.create({ container: { 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 188bfde..b80e2f2 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,4 +1,4 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; import { View, Text } from "react-native"; import { connect } from "react-redux"; @@ -15,13 +15,22 @@ import { Button } from "react-native-paper"; //temp 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 { CostCenterSelect } from "../Selects/select-cost-center"; +import { + selectCurrentTimeTicketJob, + selectCurrentTimeTicketJobId, +} from "../../redux/timetickets/timetickets.selectors"; const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, - theRates: selectRates, loaderGettingRates: selectGettingRates, signingError: selectSignInError, + currentBodyshop: selectBodyshop, + currentRatesNCostCenters: selectRates, + currentSelectedTimeTicketJobId: selectCurrentTimeTicketJobId, + currentSelectedTimeTicketJob: selectCurrentTimeTicketJob, }); const mapDispatchToProps = (dispatch) => ({ @@ -33,33 +42,83 @@ export function ScreenTimeTicketBrowser({ loaderGettingRates, currentEmployee, employeeGetRatesStart, - signingError + signingError, + currentBodyshop, + currentRatesNCostCenters, + currentSelectedTimeTicketJob, + currentSelectedTimeTicketJobId, }) { -const employeeId = currentEmployee.technician.id; + //const employeeId = currentEmployee.technician.id; + const [currentCC, setCurrentCC] = useState(null); // const { error, data } = useQuery(QUERY_EMPLOYEE_BY_ID, { // variables: { id: currentEmployee.technician.id }, // }); // const signingErrorMsg = error ? () : null; - // const signingErrorMsg = signingError ? () : null; + // const signingErrorMsg = signingError ? () : null; const getRates = (currentEmployee) => { employeeGetRatesStart(currentEmployee.technician.id); }; - + const createTheTimeTicketOBJ = ( + currentEmployee, + currentBodyshop, + currentCC + ) => { + console.log("currentCC", currentCC.value); + console.log("bodyshopid", currentBodyshop.id); + console.log("employeeid", currentEmployee.technician.id); + console.log(currentBodyshop); + // const temp = { + // timeTicketInput: [ + // { + // bodyshopid: currentBodyshop?.id, + // employeeid: currentEmployee?.technician?.id, + // 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 + // ? 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, + // }, + // ], + // }; + // console.log(temp); + //employeeGetRatesStart(currentEmployee.technician.id); + }; return ( Time Ticket List goes here - {/* {signingErrorMsg} */} + mode="outlined" + loading={loaderGettingRates} + //onPress={() => getRates(currentEmployee)} + onPress={() => + createTheTimeTicketOBJ(currentEmployee, currentBodyshop, currentCC) + } + > + text here + + {/* {signingErrorMsg} */} + + ); } -export default connect(mapStateToProps, mapDispatchToProps)(ScreenTimeTicketBrowser); \ No newline at end of file +export default connect( + mapStateToProps, + mapDispatchToProps +)(ScreenTimeTicketBrowser); diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index a9ca0e4..1a45364 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -5,7 +5,7 @@ import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { Button, Dialog, TextInput } from "react-native-paper"; -import { SelectCostCenter } from "../Selects/select-cost-center"; +import { CostCenterSelect } from "../Selects/select-cost-center"; import { JobSearchSelect } from "../Selects/select-job-name"; import DateTimePickerModal from "react-native-modal-datetime-picker"; import { @@ -31,7 +31,8 @@ export function TimeTicketCreate({ const [isDatePickerVisible, setDatePickerVisibility] = useState(false); const [date2, setDate2] = useState(new Date()); - const [costCenters, setCostCenters] = useState([]); + + const [currentCC, setCurrentCC] = useState(null); const showDatePicker = () => { setDatePickerVisibility(true); @@ -49,20 +50,6 @@ export function TimeTicketCreate({ //TODO update with start call for create time ticket }; - useEffect(() => { - if (typeof currentRatesNCostCenters !== 'undefined') { - var count = Object.keys(currentRatesNCostCenters).length; - let selectDataArray = []; - for (let i = 0; i < count; i++) { - selectDataArray.push({ - value: currentRatesNCostCenters[i].cost_center, - label: currentRatesNCostCenters[i].cost_center, - }); - } - setCostCenters(selectDataArray); - } - }, []); - return ( @@ -106,8 +93,7 @@ export function TimeTicketCreate({ label={"Employee"} /> - - + Date: Thu, 11 May 2023 15:11:32 -0400 Subject: [PATCH 040/105] updated timeticket selectors --- .../screen-main/screen-main.component.jsx | 2 +- redux/employee/employee.selectors.js | 2 +- redux/timetickets/timetickets.sagas.js | 43 ++++++++++--------- redux/timetickets/timetickets.selectors.js | 8 ++-- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/components/screen-main/screen-main.component.jsx b/components/screen-main/screen-main.component.jsx index 2cf1c86..c536eeb 100644 --- a/components/screen-main/screen-main.component.jsx +++ b/components/screen-main/screen-main.component.jsx @@ -34,7 +34,7 @@ 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-ap-time-ticket-list/screen-time-ticket-browser.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"; diff --git a/redux/employee/employee.selectors.js b/redux/employee/employee.selectors.js index a611301..b8bfe8e 100644 --- a/redux/employee/employee.selectors.js +++ b/redux/employee/employee.selectors.js @@ -16,7 +16,7 @@ export const selectSignInError = createSelector( ); export const selectRates = createSelector( [selectEmployee], - (employee) => employee.currentEmployee.technician.rates + (employee) => employee?.currentEmployee?.technician?.rates ); export const selectGettingRates = createSelector( [selectEmployee], diff --git a/redux/timetickets/timetickets.sagas.js b/redux/timetickets/timetickets.sagas.js index 7e876b3..602297e 100644 --- a/redux/timetickets/timetickets.sagas.js +++ b/redux/timetickets/timetickets.sagas.js @@ -29,32 +29,33 @@ export function* insertNewTimeTicket({ payload: { timeTicketInput } }) { // pin: pin, // }); // const { valid, data, error } = response.data; - const result = yield client.query({ - query: INSERT_NEW_TIME_TICKET, + 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 - ); - }), - }, + // { + // 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)); diff --git a/redux/timetickets/timetickets.selectors.js b/redux/timetickets/timetickets.selectors.js index 2539e99..a493260 100644 --- a/redux/timetickets/timetickets.selectors.js +++ b/redux/timetickets/timetickets.selectors.js @@ -1,16 +1,16 @@ import { createSelector } from "reselect"; -const selectTimeTicketsState = (state) => state.TimeTickets; +const selectTimeTicketsState = (state) => state.timeTickets; export const selectCurrentTimeTicketJobId = createSelector( [selectTimeTicketsState], - (TimeTickets) => TimeTickets.timeTicketJobId + (timeTickets) => timeTickets.timeTicketJobId ); export const selectCurrentTimeTicketJob = createSelector( [selectTimeTicketsState], - (TimeTickets) => TimeTickets.timeTicketJob + (timeTickets) => timeTickets.timeTicketJob ); export const selectCurrentTimeTicket = createSelector( [selectTimeTicketsState], - (TimeTickets) => TimeTickets.timeTicket + (timeTickets) => timeTickets.timeTicket ); From 2d17623bdfe987e53da920ca6c7f6393e3caa13c Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Fri, 12 May 2023 11:25:17 -0400 Subject: [PATCH 041/105] added component for testing selecting job id --- components/Selects/select-job-id.jsx | 188 ++++++++++++++++++ .../screen-time-ticket-browser.component.jsx | 43 +++- .../screen-time-ticket-create.component.jsx | 10 +- 3 files changed, 232 insertions(+), 9 deletions(-) create mode 100644 components/Selects/select-job-id.jsx diff --git a/components/Selects/select-job-id.jsx b/components/Selects/select-job-id.jsx new file mode 100644 index 0000000..49f54cd --- /dev/null +++ b/components/Selects/select-job-id.jsx @@ -0,0 +1,188 @@ +import { useLazyQuery } from "@apollo/client"; +import React, { forwardRef, useState, useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import _ from "lodash"; + +import { + SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE, + SEARCH_JOBS_FOR_AUTOCOMPLETE, +} from "../../graphql/jobs.queries"; +import { StyleSheet, Text, View } from "react-native"; +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 +) { + const { t } = useTranslation(); + const [theOptions, setTheOptions] = useState([]); + + const [selectorData, setSelectorData] = useState([]); + const [selectedvalue, setSelectedValue] = useState(null); + const [isFocus, setIsFocus] = useState(false); + + 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); + if (v && v !== "") callSearch(v); + }; + const debouncedExecuteSearch = _.debounce(executeSearch, 500); + + const handleSearch = (value) => { + console.log("handleSearchWithValue:", value); + debouncedExecuteSearch({ + variables: { + search: value, + ...(convertedOnly || notExported + ? { + ...(convertedOnly ? { isConverted: true } : {}), + ...(notExported ? { notExported: true } : {}), + ...(notInvoiced ? { notInvoiced: true } : {}), + } + : {}), + }, + }); + }; + + 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" + ) + ); + }, [data, idData]); + + useEffect(() => { + console.log("useEfectDependentOn: [theOptions]"); + var count = Object.keys(theOptions).length; + 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 || "" + // }`, + + }); + } + setSelectorData(selectDataArray); + }, [theOptions]); + + + return ( + + setIsFocus(true)} + onBlur={() => setIsFocus(false)} + onChange={(item) => { + console.log("onChangefired!!!!"); + console.log("itemSelected", item); + setSelectedValue(item.value); + // onValueSelected(item); + //console.log(item); + // setSelectedValue(item.value); + // if (onValueSelected) onValueSelected(item.value); + setIsFocus(false); + }} + onChangeText={(search) => { + console.log("onChangeTextFired!!!!"); + handleSearch(search); + }} + /> + {/* {theOptions ? console.log(theOptions): null} */} + + ); +} + +export default connect(null, null)(JobIdSearchSelect); + +const styles = StyleSheet.create({ + container: { + padding: 16, + justifyContent: "center", + alignContent: "center", + }, + dropdown: { + height: 50, + borderColor: "gray", + borderWidth: 0.5, + borderRadius: 8, + paddingHorizontal: 8, + }, + icon: { + marginRight: 5, + }, + label: { + position: "absolute", + backgroundColor: "white", + left: 22, + top: 8, + zIndex: 999, + paddingHorizontal: 8, + fontSize: 14, + }, + placeholderStyle: { + fontSize: 16, + }, + selectedTextStyle: { + fontSize: 16, + }, + iconStyle: { + width: 20, + height: 20, + }, + inputSearchStyle: { + height: 40, + fontSize: 16, + }, +}); 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 b80e2f2..66e232b 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,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useCallback, useEffect, useState } from "react"; import { View, Text } from "react-native"; import { connect } from "react-redux"; @@ -22,6 +22,7 @@ import { selectCurrentTimeTicketJob, selectCurrentTimeTicketJobId, } from "../../redux/timetickets/timetickets.selectors"; +import { JobIdSearchSelect } from "../Selects/select-job-id"; const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, @@ -49,7 +50,9 @@ export function ScreenTimeTicketBrowser({ currentSelectedTimeTicketJobId, }) { //const employeeId = currentEmployee.technician.id; - const [currentCC, setCurrentCC] = useState(null); + const [currentSCC, setCurrentSCC] = useState(null); + const [currentSJob, setCurrentSJob] = useState(null); + const [currentSJobId, setCurrentSJobId] = useState(null); // const { error, data } = useQuery(QUERY_EMPLOYEE_BY_ID, { // variables: { id: currentEmployee.technician.id }, @@ -57,15 +60,24 @@ export function ScreenTimeTicketBrowser({ // const signingErrorMsg = error ? () : null; // const signingErrorMsg = signingError ? () : null; + const wrapperSetCurrentSJobState = useCallback(val => { + setCurrentSJob(val); + }, [setCurrentSJob]); + + const getRates = (currentEmployee) => { employeeGetRatesStart(currentEmployee.technician.id); }; const createTheTimeTicketOBJ = ( currentEmployee, currentBodyshop, - currentCC + currentSCC, + currentSJob, + currentSJobId ) => { - console.log("currentCC", currentCC.value); + 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); @@ -99,21 +111,38 @@ export function ScreenTimeTicketBrowser({ loading={loaderGettingRates} //onPress={() => getRates(currentEmployee)} onPress={() => - createTheTimeTicketOBJ(currentEmployee, currentBodyshop, currentCC) + createTheTimeTicketOBJ(currentEmployee, currentBodyshop, currentSCC) } > text here {/* {signingErrorMsg} */} + + + ); } diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index 1a45364..50e629c 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -13,6 +13,7 @@ import { selectRates, } from "../../redux/employee/employee.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; +import { useCallback } from "react"; //TODO add props needed for call const mapStateToProps = createStructuredSelector({ @@ -32,7 +33,12 @@ export function TimeTicketCreate({ const [isDatePickerVisible, setDatePickerVisibility] = useState(false); const [date2, setDate2] = useState(new Date()); - const [currentCC, setCurrentCC] = useState(null); + const [currentSCC, setCurrentSCC] = useState(null); + const [currentSJob, setCurrentSJob] = useState(null); + + const wrapperSetCurrentSJobState = useCallback(val => { + setCurrentSJob(val); + }, [setCurrentSJob]); const showDatePicker = () => { setDatePickerVisibility(true); @@ -93,7 +99,7 @@ export function TimeTicketCreate({ label={"Employee"} /> - + Date: Sat, 13 May 2023 13:56:44 -0400 Subject: [PATCH 042/105] 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 From 6d852453b0a21c07fb126ad2f6c8ac707bcd2c9e Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Sun, 14 May 2023 11:59:34 -0400 Subject: [PATCH 043/105] added labor allocationtable --- components/Selects/select-cost-center.jsx | 5 +- .../labor-allocations-table.component.jsx | 215 +++++++++++++++--- .../screen-time-ticket-create.component.jsx | 44 ++-- graphql/jobs.queries.js | 48 ++++ translations/en-US/common.json | 90 ++++++++ translations/es-MX/common.json | 90 ++++++++ translations/fr-CA/common.json | 90 ++++++++ util/labor-allocations-table.utility.js | 54 +++++ 8 files changed, 591 insertions(+), 45 deletions(-) create mode 100644 util/labor-allocations-table.utility.js diff --git a/components/Selects/select-cost-center.jsx b/components/Selects/select-cost-center.jsx index 81abd44..136c076 100644 --- a/components/Selects/select-cost-center.jsx +++ b/components/Selects/select-cost-center.jsx @@ -77,12 +77,13 @@ export default connect(null, null)(CostCenterSelect); const styles = StyleSheet.create({ container: { - padding: 16, + marginVertical: 4, + marginHorizontal: 16, justifyContent: "center", alignContent: "center", }, dropdown: { - height: 50, + height: 48, borderColor: "gray", borderWidth: 0.5, borderRadius: 8, diff --git a/components/labor-allocations-table/labor-allocations-table.component.jsx b/components/labor-allocations-table/labor-allocations-table.component.jsx index b7ec0c5..e1096f3 100644 --- a/components/labor-allocations-table/labor-allocations-table.component.jsx +++ b/components/labor-allocations-table/labor-allocations-table.component.jsx @@ -1,23 +1,183 @@ -import React from "react"; +import React, { useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { FlatList, RefreshControl, StyleSheet, Text, View } from "react-native"; +import _ from "lodash"; 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"; +import { createStructuredSelector } from "reselect"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +import { selectCurrentEmployee } from "../../redux/employee/employee.selectors"; +import { CalculateAllocationsTotals } from "../../util/labor-allocations-table.utility"; -export default function LaborAllocationsTable({ job, loading, refetch }) { - const { t } = useTranslation(); - - if (!job) { - - Job is not defined. - ; - } - const onRefresh = async () => { - return refetch(); - }; - - return ( - - +const mapStateToProps = createStructuredSelector({ + bodyshop: selectBodyshop, + technician: selectCurrentEmployee, +}); + +export function LaborAllocationsTable({ jobId, bodyshop, technician }) { + console.log("LaborAllocationsTable, jobId", jobId); + //, loading, refetch + //const jobid = jobid !== undefined ? jobid : ""; + const { t } = useTranslation(); + + const onRefresh = async () => { + + console.log("LaborAllocationsTable refetch"); + return refetch(); + }; + + //maybe use this + const { loading, error, data, refetch } = useQuery(GET_LINE_TICKET_BY_PK, { + variables: { id: jobId }, + skip: !!!jobId, + fetchPolicy: "network-only", + nextFetchPolicy: "network-only", + }); + + // console.log("LaborAllocationsTable, data", data); + if (error) return ; + + // let joblines = []; + // let timetickets = []; + // let adjustments = []; + + const [totals, setTotals] = useState([]); + const [state, setState] = useState({ + sortedInfo: { + columnKey: "cost_center", + field: "cost_center", + order: "ascend", + }, + filteredInfo: {}, + }); + + useEffect(() => { + console.log("LaborAllocationsTable useEffect on data change"); + // joblines = data?.joblines ? data.joblines : []; + // timetickets = data?.timetickets ? data.timetickets : []; + // adjustments = data?.adjustments ? data.adjustments : []; + }, [data]); + + useEffect(() => { + console.log( + "LaborAllocationsTable useEffect on [joblines, timetickets, bodyshop, adjustments, jobId] change", + data?.joblines, + data?.adjustments + ); + if (!!data?.joblines && !!data?.timetickets && !!bodyshop) + setTotals( + CalculateAllocationsTotals( + bodyshop, + data?.joblines, + data?.timetickets, + data?.adjustments + ) + ); + if (!jobId) setTotals([]); + }, [data?.joblines, data?.timetickets, bodyshop, data?.adjustments, jobId]); + + // const convertedLines = useMemo( + // () => data?.joblines && data?.joblines.filter((j) => j.convertedtolbr), + // [data?.joblines] + // ); + + const summary = + totals && + totals.reduce( + (acc, val) => { + acc.hrs_total += val.total; + acc.hrs_claimed += val.claimed; + acc.adjustments += val.adjustments; + acc.difference += val.difference; + return acc; + }, + { hrs_total: 0, hrs_claimed: 0, adjustments: 0, difference: 0 } + ); + + console.log("labor summary is:", summary); + + return ( + + {typeof data !== "undefined" ? ( + + + + Cost Center + + Hours Total + + + Hours Claimed + + + Adjustments + + + Difference + + + + + + } + keyExtractor={(item) => item.cost_center} + renderItem={(object) => ( + + + + + {object.item.cost_center} + {object.item.mod_lbr_ty} + + + + {object.item.total && object.item.total.toFixed(1)} + + + {object.item.claimed && object.item.claimed.toFixed(1)} + + + + {object.item.adjustments && object.item.adjustments.toFixed(1)} + {/* {!technician && ( + + + + )} */} + + + + = 0 ? "green" : "red", + }}> + {/* = 0 ? "green" : "red", + }} + > + {_.round(object.difference, 1)} + */} + {_.round(object.item.difference, 1)} + + + + )} + /> + + + ) : null} + {/* {t("jobdetail.labels.lines_desc")} @@ -35,9 +195,9 @@ export default function LaborAllocationsTable({ job, loading, refetch }) { {t("jobdetail.labels.lines_qty")} - - - */} + + {/* @@ -64,10 +224,13 @@ export default function LaborAllocationsTable({ job, loading, refetch }) { )} - /> - - ); - } - - const localStyles = StyleSheet.create({}); - \ No newline at end of file + /> */} + + {/* use "totals" for the rows in the table */} + {/* use "summary" for the totals at the bottom */} + + ); +} + +const localStyles = StyleSheet.create({}); +export default connect(mapStateToProps, null)(LaborAllocationsTable); diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index b016ab0..3d051ac 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -14,6 +14,8 @@ import { } from "../../redux/employee/employee.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; import { useCallback } from "react"; +// import LaborAllocationsTable from "../labor-allocations-table/labor-allocations-table.component"; +import LaborAllocationsTable from "../labor-allocations-table/labor-allocations-table.component"; //TODO add props needed for call const mapStateToProps = createStructuredSelector({ @@ -34,15 +36,15 @@ export function TimeTicketCreate({ const [date2, setDate2] = useState(new Date()); const [currentSCC, setCurrentSCC] = useState(null); - const [currentSJob, setCurrentSJob] = 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); @@ -56,19 +58,20 @@ export function TimeTicketCreate({ hideDatePicker(); }; const formSubmit = (values) => { - Dialog.alert({ content:
{JSON.stringify(values, null, 2)}
}); + console.log("values", values); + //Dialog.alert({ content:
{JSON.stringify(values, null, 2)}
}); //TODO update with start call for create time ticket }; return ( - + {/* Below is for list of jobs/tickets */} - + + + + + + ); } @@ -159,12 +167,13 @@ const localStyles = StyleSheet.create({ display: "flex", flex: 1, }, - topTimeTicketContainer: {}, - bottomTimeTicketContainer: {}, + topContainer: {}, + bottomContainer: {}, input: {}, dateButton: { - margin: 16, - height: 40, + marginVertical: 4, + marginHorizontal: 16, + height: 48, justifyContent: "center", alignContent: "center", borderColor: "blue", @@ -177,7 +186,8 @@ const localStyles = StyleSheet.create({ alignContent: "center", }, inputStyle: { - margin: 16, + marginVertical: 4, + marginHorizontal: 16, height: 48, fontSize: 16, }, diff --git a/graphql/jobs.queries.js b/graphql/jobs.queries.js index d56fa26..22adc17 100644 --- a/graphql/jobs.queries.js +++ b/graphql/jobs.queries.js @@ -923,6 +923,54 @@ export const QUERY_JOB_CLOSE_DETAILS = gql` } `; +export const GET_LINE_TICKET_BY_PK = gql` + query GET_LINE_TICKET_BY_PK($id: uuid!) { + jobs_by_pk(id: $id) { + id + lbr_adjustments + converted + } + joblines(where: { jobid: { _eq: $id }, removed: { _eq: false } }) { + id + line_desc + 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 + convertedtolbr + convertedtolbr_data + } + timetickets(where: { jobid: { _eq: $id } }) { + actualhrs + ciecacode + cost_center + date + id + jobid + employeeid + memo + flat_rate + clockon + clockoff + rate + employee { + id + first_name + last_name + employee_number + } + productivehrs + } + } +`; + export const generate_UPDATE_JOB_KANBAN = ( oldChildId, oldChildNewParent, diff --git a/translations/en-US/common.json b/translations/en-US/common.json index 7929c3b..c3af9b5 100644 --- a/translations/en-US/common.json +++ b/translations/en-US/common.json @@ -360,6 +360,96 @@ "titles": { "createtimeticket": "Create a Time Ticket" } + }, + "joblines": { + "actions": { + "converttolabor": "Convert amount to Labor.", + "new": "New Line" + }, + "errors": { + "creating": "Error encountered while creating job line. {{message}}", + "updating": "Error encountered updating job line. {{message}}" + }, + "fields": { + "act_price": "Retail Price", + "ah_detail_line": "Mark as Detail Labor Line (Autohouse Only)", + "db_price": "List Price", + "lbr_types": { + "LA1": "LA1", + "LA2": "LA2", + "LA3": "LA3", + "LA4": "LA4", + "LAA": "Aluminum", + "LAB": "Body", + "LAD": "Diagnostic", + "LAE": "Electrical", + "LAF": "Frame", + "LAG": "Glass", + "LAM": "Mechanical", + "LAR": "Refinish", + "LAS": "Structural", + "LAU": "User Defined" + }, + "line_desc": "Line Desc.", + "line_ind": "S#", + "line_no": "Line #", + "location": "Location", + "mod_lb_hrs": "Hrs", + "mod_lbr_ty": "Labor Type", + "notes": "Notes", + "oem_partno": "OEM Part #", + "op_code_desc": "Op Code Description", + "part_qty": "Qty.", + "part_type": "Part Type", + "part_types": { + "CCC": "CC Cleaning", + "CCD": "CC Damage Waiver", + "CCDR": "CC Daily Rate", + "CCF": "CC Refuel", + "CCM": "CC Mileage", + "PAA": "Aftermarket", + "PAC": "Rechromed", + "PAE": "Existing", + "PAG": "Glass", + "PAL": "LKQ", + "PAM": "Remanufactured", + "PAN": "New/OEM", + "PAO": "Other", + "PAP": "OEM Partial", + "PAR": "Recored", + "PAS": "Sublet", + "PASL": "Sublet (L)" + }, + "profitcenter_labor": "Profit Center: Labor", + "profitcenter_part": "Profit Center: Part", + "prt_dsmk_m": "Line Discount/Markup $", + "prt_dsmk_p": "Line Discount/Markup %", + "status": "Status", + "tax_part": "Tax Part", + "total": "Total", + "unq_seq": "Seq #" + }, + "labels": { + "adjustmenttobeadded": "Adjustment to be added: {{adjustment}}", + "billref": "Latest Bill", + "convertedtolabor": "This line has been converted to labor. Ensure you adjust the profit center for the amount accordingly.", + "edit": "Edit Line", + "ioucreated": "IOU", + "new": "New Line", + "nostatus": "No Status", + "presets": "Jobline Presets" + }, + "successes": { + "created": "Job line created successfully.", + "saved": "Job line saved.", + "updated": "Job line updated successfully." + }, + "validations": { + "ahdetailonlyonuserdefinedtypes": "Detail line indicator can only be set for LA1, LA2, LA3, LA4, and LAU labor types.", + "hrsrequirediflbrtyp": "Labor hours are required if a labor type is selected. Clear the labor type if there are no labor hours.", + "requiredifparttype": "Required if a part type has been specified.", + "zeropriceexistingpart": "This line cannot have any price since it uses an existing part." + } } } } diff --git a/translations/es-MX/common.json b/translations/es-MX/common.json index 88a4f1a..0d4aac5 100644 --- a/translations/es-MX/common.json +++ b/translations/es-MX/common.json @@ -360,6 +360,96 @@ "titles": { "createtimeticket": "" } + }, + "joblines": { + "actions": { + "converttolabor": "", + "new": "" + }, + "errors": { + "creating": "", + "updating": "" + }, + "fields": { + "act_price": "Precio actual", + "ah_detail_line": "", + "db_price": "Precio de base de datos", + "lbr_types": { + "LA1": "", + "LA2": "", + "LA3": "", + "LA4": "", + "LAA": "", + "LAB": "", + "LAD": "", + "LAE": "", + "LAF": "", + "LAG": "", + "LAM": "", + "LAR": "", + "LAS": "", + "LAU": "" + }, + "line_desc": "Descripción de línea", + "line_ind": "S#", + "line_no": "", + "location": "", + "mod_lb_hrs": "Horas laborales", + "mod_lbr_ty": "Tipo de trabajo", + "notes": "", + "oem_partno": "OEM parte #", + "op_code_desc": "", + "part_qty": "", + "part_type": "Tipo de parte", + "part_types": { + "CCC": "", + "CCD": "", + "CCDR": "", + "CCF": "", + "CCM": "", + "PAA": "", + "PAC": "", + "PAE": "", + "PAG": "", + "PAL": "", + "PAM": "", + "PAN": "", + "PAO": "", + "PAP": "", + "PAR": "", + "PAS": "", + "PASL": "" + }, + "profitcenter_labor": "", + "profitcenter_part": "", + "prt_dsmk_m": "", + "prt_dsmk_p": "", + "status": "Estado", + "tax_part": "", + "total": "", + "unq_seq": "Seq #" + }, + "labels": { + "adjustmenttobeadded": "", + "billref": "", + "convertedtolabor": "", + "edit": "Línea de edición", + "ioucreated": "", + "new": "Nueva línea", + "nostatus": "", + "presets": "" + }, + "successes": { + "created": "", + "saved": "", + "updated": "" + }, + "validations": { + "ahdetailonlyonuserdefinedtypes": "", + "hrsrequirediflbrtyp": "", + "requiredifparttype": "", + "zeropriceexistingpart": "" + } } } } diff --git a/translations/fr-CA/common.json b/translations/fr-CA/common.json index a1d1cad..efb30bd 100644 --- a/translations/fr-CA/common.json +++ b/translations/fr-CA/common.json @@ -360,6 +360,96 @@ "titles": { "createtimeticket": "" } + }, + "joblines": { + "actions": { + "converttolabor": "", + "new": "" + }, + "errors": { + "creating": "", + "updating": "" + }, + "fields": { + "act_price": "Prix actuel", + "ah_detail_line": "", + "db_price": "Prix de la base de données", + "lbr_types": { + "LA1": "", + "LA2": "", + "LA3": "", + "LA4": "", + "LAA": "", + "LAB": "", + "LAD": "", + "LAE": "", + "LAF": "", + "LAG": "", + "LAM": "", + "LAR": "", + "LAS": "", + "LAU": "" + }, + "line_desc": "Description de la ligne", + "line_ind": "S#", + "line_no": "", + "location": "", + "mod_lb_hrs": "Heures de travail", + "mod_lbr_ty": "Type de travail", + "notes": "", + "oem_partno": "Pièce OEM #", + "op_code_desc": "", + "part_qty": "", + "part_type": "Type de pièce", + "part_types": { + "CCC": "", + "CCD": "", + "CCDR": "", + "CCF": "", + "CCM": "", + "PAA": "", + "PAC": "", + "PAE": "", + "PAG": "", + "PAL": "", + "PAM": "", + "PAN": "", + "PAO": "", + "PAP": "", + "PAR": "", + "PAS": "", + "PASL": "" + }, + "profitcenter_labor": "", + "profitcenter_part": "", + "prt_dsmk_m": "", + "prt_dsmk_p": "", + "status": "Statut", + "tax_part": "", + "total": "", + "unq_seq": "Seq #" + }, + "labels": { + "adjustmenttobeadded": "", + "billref": "", + "convertedtolabor": "", + "edit": "Ligne d'édition", + "ioucreated": "", + "new": "Nouvelle ligne", + "nostatus": "", + "presets": "" + }, + "successes": { + "created": "", + "saved": "", + "updated": "" + }, + "validations": { + "ahdetailonlyonuserdefinedtypes": "", + "hrsrequirediflbrtyp": "", + "requiredifparttype": "", + "zeropriceexistingpart": "" + } } } } diff --git a/util/labor-allocations-table.utility.js b/util/labor-allocations-table.utility.js new file mode 100644 index 0000000..368e2cd --- /dev/null +++ b/util/labor-allocations-table.utility.js @@ -0,0 +1,54 @@ +import i18next from "i18next"; +import React from "react"; + +export const CalculateAllocationsTotals = ( + bodyshop, + joblines, + timetickets, + adjustments = [] +) => { +// console.log("🚀 ~ file: adjustments", adjustments); +// console.log("🚀 ~ file: bodyshop", bodyshop); + console.log("🚀 ~ file: joblines", joblines); +// console.log("🚀 ~ file: timetickets", timetickets); + const responsibilitycenters = bodyshop.md_responsibility_centers; + const jobCodes = joblines.map((item) => item.mod_lbr_ty); + console.log("jobCodes :", jobCodes); + //.filter((value, index, self) => self.indexOf(value) === index && !!value); + const ticketCodes = timetickets.map((item) => item.ciecacode); + console.log("ticketCodes :", ticketCodes); + //.filter((value, index, self) => self.indexOf(value) === index && !!value); + const adjustmentCodes = Object.keys(adjustments); + console.log("adjustmentCodes :", adjustmentCodes); + const allCodes = [...jobCodes, ...ticketCodes, ...adjustmentCodes].filter( + (value, index, self) => self.indexOf(value) === index && !!value + ); + console.log("allCodes :", allCodes); + + const r = allCodes.reduce((acc, value) => { + const r = { + opcode: value, + cost_center: + bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber + ? i18next.t( + `joblines.fields.lbr_types.${value && value.toUpperCase()}` + ) + : responsibilitycenters.defaults.costs[value], + mod_lbr_ty: value, + total: joblines.reduce((acc2, val2) => { + return val2.mod_lbr_ty === value ? acc2 + val2.mod_lb_hrs : acc2; + }, 0), + adjustments: adjustments[value] || 0, + claimed: timetickets.reduce((acc3, val3) => { + return val3.ciecacode === value ? acc3 + val3.productivehrs : acc3; + }, 0), + }; + + r.difference = r.total + r.adjustments - r.claimed; + acc.push(r); + return acc; + }, []); + console.log(" r is :", r); + + return r; +}; From be9d285ac96f2bf9bd49f5eb4cf5e3cc93a59ca6 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Sun, 14 May 2023 14:30:07 -0400 Subject: [PATCH 044/105] added totals to labor allocations --- .../labor-allocations-table.component.jsx | 81 ++++++++++++------- util/labor-allocations-table.utility.js | 2 +- 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/components/labor-allocations-table/labor-allocations-table.component.jsx b/components/labor-allocations-table/labor-allocations-table.component.jsx index e1096f3..df2790b 100644 --- a/components/labor-allocations-table/labor-allocations-table.component.jsx +++ b/components/labor-allocations-table/labor-allocations-table.component.jsx @@ -2,7 +2,7 @@ import React, { useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { FlatList, RefreshControl, StyleSheet, Text, View } from "react-native"; import _ from "lodash"; -import { Card, DataTable } from "react-native-paper"; +import { Card, DataTable, Divider } 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"; @@ -104,21 +104,15 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician }) { {typeof data !== "undefined" ? ( - - Cost Center - - Hours Total - - - Hours Claimed - - - Adjustments - - - Difference - - + + Cost Center + Hours Total + Hours Claimed + {/* Hours Claimed */} + Adjustments + Difference + + } keyExtractor={(item) => item.cost_center} + ItemSeparatorComponent={} renderItem={(object) => ( - + - {object.item.cost_center} - {object.item.mod_lbr_ty} + {object.item.cost_center} {" ("} + {object.item.mod_lbr_ty}{")"} - - + + {object.item.total && object.item.total.toFixed(1)} - - + + {object.item.claimed && object.item.claimed.toFixed(1)} - - + + {object.item.adjustments && object.item.adjustments.toFixed(1)} {/* {!technician && ( @@ -156,10 +151,10 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician }) { )} */} - - + + = 0 ? "green" : "red", + color: object.item.difference >= 0 ? "green" : "red", }}> {/* */} {_.round(object.item.difference, 1)} - + )} /> + {summary && ( + Totals + {summary.hrs_total.toFixed(1)} + {summary.hrs_claimed.toFixed(1)} + {summary.adjustments.toFixed(1)} + {summary.difference.toFixed(1)} + ) + }
) : null} @@ -232,5 +235,23 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician }) { ); } -const localStyles = StyleSheet.create({}); +const localStyles = StyleSheet.create({ +headerArea:{ + flexDirection:"row", + justifyContent:"center", + alignItems:"center", + margin:1 +}, +footertext:{ + flex:1, textAlign:'center', textAlignVertical:'center',margin:1 +}, +headertext:{ + flex:1, textAlign:'center', textAlignVertical:'center',backgroundColor:'blue',margin:1 +}, +headertextAdjusts:{ + flex:1, textAlign:'center', textAlignVertical:'center',backgroundColor:'green',margin:1 +}, + + +}); export default connect(mapStateToProps, null)(LaborAllocationsTable); diff --git a/util/labor-allocations-table.utility.js b/util/labor-allocations-table.utility.js index 368e2cd..30deccd 100644 --- a/util/labor-allocations-table.utility.js +++ b/util/labor-allocations-table.utility.js @@ -9,7 +9,7 @@ export const CalculateAllocationsTotals = ( ) => { // console.log("🚀 ~ file: adjustments", adjustments); // console.log("🚀 ~ file: bodyshop", bodyshop); - console.log("🚀 ~ file: joblines", joblines); +// console.log("🚀 ~ file: joblines", joblines); // console.log("🚀 ~ file: timetickets", timetickets); const responsibilitycenters = bodyshop.md_responsibility_centers; const jobCodes = joblines.map((item) => item.mod_lbr_ty); From d19bc10865dec71a34499869f051d1484536ccef Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Sun, 14 May 2023 21:02:09 -0400 Subject: [PATCH 045/105] added missing fuctionallity --- .../job-list-item/job-list-item.component.jsx | 6 +- ...-allocations-table-container.component.jsx | 43 ++++ .../labor-allocations-table.component.jsx | 6 +- .../screen-main/screen-main.component.jsx | 14 +- .../screen-time-ticket-browser.component.jsx | 9 +- .../clockedin-list-item.component.jsx | 78 +++++-- .../employee-clockedin-list.component.jsx | 5 +- .../screen-time-ticket-clockoff.component.jsx | 218 ++++++++++++++++++ .../screen-time-ticket-create.component.jsx | 2 + redux/app/app.actions.js | 5 + redux/app/app.reducer.js | 6 + redux/app/app.selectors.js | 5 + redux/app/app.types.js | 1 + redux/root.saga.js | 2 +- redux/timetickets/timetickets.actions.js | 1 + redux/timetickets/timetickets.reducer.js | 16 +- redux/timetickets/timetickets.sagas.js | 66 +++--- redux/timetickets/timetickets.selectors.js | 1 + 18 files changed, 397 insertions(+), 87 deletions(-) create mode 100644 components/labor-allocations-table/labor-allocations-table-container.component.jsx create mode 100644 components/time-ticket/screen-time-ticket-clockoff.component.jsx 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 ); + From e1d72ad355a2ae746ff248df663c55e98b9885d6 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 15 May 2023 02:36:35 -0400 Subject: [PATCH 046/105] added parts for last 3 calls --- .../tech-clock-out-button.component.jsx | 28 +++++ .../job-list-item/job-list-item.component.jsx | 8 +- .../clockedin-list-item.component.jsx | 118 +++++++++++------- .../employee-clockedin-list.component.jsx | 38 ++++-- .../screen-time-ticket-clockoff.component.jsx | 5 +- redux/timetickets/timetickets.actions.js | 26 ++++ redux/timetickets/timetickets.reducer.js | 39 ++++-- redux/timetickets/timetickets.sagas.js | 71 ++++++++++- redux/timetickets/timetickets.types.js | 6 + 9 files changed, 264 insertions(+), 75 deletions(-) create mode 100644 components/Buttons/tech-clock-out-button.component.jsx diff --git a/components/Buttons/tech-clock-out-button.component.jsx b/components/Buttons/tech-clock-out-button.component.jsx new file mode 100644 index 0000000..19fd1ae --- /dev/null +++ b/components/Buttons/tech-clock-out-button.component.jsx @@ -0,0 +1,28 @@ +import React from "react"; +import { Text } from "react-native"; +import { Button } from "react-native-paper"; +import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; +import { employeeSignOut } from "../../redux/employee/employee.actions"; +import { setTmTicketJobId } from "../../redux/app/app.actions"; + +const mapDispatchToProps = (dispatch) => ({ + signOut:(jobId) => dispatch(setTmTicketJobId()), +}); + +export function TechClockOffButton({ setTmTicketJobId, + jobId, + timeTicketId, }) { + const { t } = useTranslation(); + return ( + + ); +} +export default connect(null, mapDispatchToProps)(SignOutButton); diff --git a/components/job-list-item/job-list-item.component.jsx b/components/job-list-item/job-list-item.component.jsx index 9d823b3..a91856f 100644 --- a/components/job-list-item/job-list-item.component.jsx +++ b/components/job-list-item/job-list-item.component.jsx @@ -6,16 +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, setTmTicketJobId } from "../../redux/app/app.actions"; +import { setCameraJob, setCameraJobId } 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)), + // setTmTicketJobId:(id) => dispatch(setTmTicketJobId(id)), }); -export function JobListItem({ setCameraJob, setCameraJobId,setTmTicketJobId, item }) { +export function JobListItem({ setCameraJob, setCameraJobId, item }) { const { t } = useTranslation(); const navigation = useNavigation(); // const _swipeableRow = useRef(null); @@ -72,7 +72,7 @@ export function JobListItem({ setCameraJob, setCameraJobId,setTmTicketJobId, ite onPress={() => { logImEXEvent("imexmobile_setcamerajobid_row"); setCameraJobId(item.id); - setTmTicketJobId(item.id); + // setTmTicketJobId(item.id); setCameraJob(item); navigation.navigate("MediaBrowserTab"); }} diff --git a/components/time-ticket-items/clockedin-list-item.component.jsx b/components/time-ticket-items/clockedin-list-item.component.jsx index f93a741..4d92c93 100644 --- a/components/time-ticket-items/clockedin-list-item.component.jsx +++ b/components/time-ticket-items/clockedin-list-item.component.jsx @@ -3,64 +3,84 @@ import { useNavigation } from "@react-navigation/native"; import React from "react"; import { useTranslation } from "react-i18next"; import { Button, Card, Text } from "react-native-paper"; -import { connect } from "react-redux"; -import { createStructuredSelector } from "reselect"; +import { connect, useSelector, useDispatch } from "react-redux"; +import { createSelector, createStructuredSelector } from "reselect"; import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component"; import { DateTimeFormatter } from "../../util/DateFormater"; // import { setTimeTicketJobId } from "../../redux/timetickets/timetickets.actions"; import { setTmTicketJobId } from "../../redux/app/app.actions"; import { logImEXEvent } from "../../firebase/firebase.analytics"; +import { employeeSignInStart } from "../../redux/employee/employee.actions"; +import { useRef } from "react"; + + +// const selectNumCompletedTodos = createSelector( +// (state) => state.timeTickets, +// (timeTickets) => timeTickets.timeTicketJobId +// ); +//const mapStateToProps = createStructuredSelector({}); + // // setTimeTicketJobId: (jobId) =>dispatch(setTimeTicketJobId({jobId})), + //employeeSignInStart:(idjob) => dispatch(employeeSignInStart(idjob)), -const mapStateToProps = createStructuredSelector({}); const mapDispatchToProps = (dispatch) => ({ - // setTimeTicketJobId: (jobId) =>dispatch(setTimeTicketJobId({jobId})), - setTmTicketJobId:(id) => dispatch(setTmTicketJobId(id)), + setTmTicketJobId:() => dispatch(setTmTicketJobId(jobId)), }); -export function ClockedinListItem({ setTmTicketJobId, ticket }) { +export function ClockedinListItem( props ) { + const { t } = useTranslation(); const navigation = useNavigation(); - - 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");} - }; + console.log("ClockedinListItem, ", props.ticket.job.id); + const jbId = props.ticket.job.id; + console.log("ClockedinListItem, jbId: ", jbId); + const te = useRef(jbId) + let makeNave = (jobId) => ( + console.log("ClockedinListItem ", setTmTicketJobId) + ,console.log("te", jobId) + ,setTmTicketJobId(jobId) + + // ,navigation.navigate("TimeTicketClockOff") + ); + // 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 ( Vehicle : - {`${ticket.job.v_model_yr || ""} ${ticket.job.v_make_desc || ""} ${ - ticket.job.v_model_desc || "" + {`${props.ticket.job.v_model_yr || ""} ${props.ticket.job.v_make_desc || ""} ${ + props.ticket.job.v_model_desc || "" }`} - Clocked In : {ticket.clockon} + Clocked In : {props.ticket.clockon} Cost Center :{" "} - {ticket.cost_center === "timetickets.labels.shift" - ? t(ticket.cost_center) - : ticket.cost_center} + {props.ticket.cost_center === "timetickets.labels.shift" + ? t(props.ticket.cost_center) + : props.ticket.cost_center} @@ -70,21 +90,25 @@ export function ClockedinListItem({ setTmTicketJobId, ticket }) { completedCallback={refetch} /> */} @@ -121,4 +145,4 @@ export function ClockedinListItem({ setTmTicketJobId, ticket }) { ); } -export default connect(mapStateToProps, mapDispatchToProps)(ClockedinListItem); +export default connect(null, mapDispatchToProps)(ClockedinListItem); diff --git a/components/time-ticket-lists/employee-clockedin-list.component.jsx b/components/time-ticket-lists/employee-clockedin-list.component.jsx index f2ebd68..ec1b2cd 100644 --- a/components/time-ticket-lists/employee-clockedin-list.component.jsx +++ b/components/time-ticket-lists/employee-clockedin-list.component.jsx @@ -1,24 +1,32 @@ import { connect } from "react-redux"; -import { selectCurrentEmployee, selectTechnician } from "../../redux/employee/employee.selectors"; +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 { ActivityIndicator } from "react-native-paper"; import ErrorDisplay from "../error-display/error-display.component"; -import { View,Text,FlatList, RefreshControl, } from "react-native"; +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"; +import { setTmTicketJobId } from "../../redux/app/app.actions"; const mapStateToProps = createStructuredSelector({ technician: selectTechnician, //currentEmployee: selectCurrentEmployee, }); -const mapDispatchToProps = (dispatch) => ({}); +const mapDispatchToProps = (dispatch) => ({ + setTmTicketJobId: (jobId) => dispatch(setTmTicketJobId(jobId)), +}); export function EmployeeClockedInList({ technician }) { - const { t } = useTranslation(); + const { t } = useTranslation(); - const { loading, error, data, refetch } = useQuery(QUERY_ACTIVE_TIME_TICKETS, { + const { loading, error, data, refetch } = useQuery( + QUERY_ACTIVE_TIME_TICKETS, + { variables: { employeeId: technician?.id, }, @@ -30,9 +38,9 @@ export function EmployeeClockedInList({ technician }) { if (loading) return ; if (error) return ; //if (error) return ; -console.log("QUERY_ACTIVE_TIME_TICKETS data",data) - -const onRefresh = async () => { + console.log("QUERY_ACTIVE_TIME_TICKETS data", data); +// if (data) () => {setTmTicketJobId(data)} + const onRefresh = async () => { return refetch(); }; return ( @@ -40,9 +48,13 @@ const onRefresh = async () => { {data.timetickets.length > 0 ? ( You are already clocked in to the following job(s): - } - renderItem={(object) => } /> + + } + renderItem={(object) => } + /> ) : null}
@@ -105,4 +117,4 @@ const onRefresh = async () => { ); } -export default connect(mapStateToProps,null)(EmployeeClockedInList); +export default connect(mapStateToProps, mapDispatchToProps)(EmployeeClockedInList); diff --git a/components/time-ticket/screen-time-ticket-clockoff.component.jsx b/components/time-ticket/screen-time-ticket-clockoff.component.jsx index 01a99a8..b86fdc5 100644 --- a/components/time-ticket/screen-time-ticket-clockoff.component.jsx +++ b/components/time-ticket/screen-time-ticket-clockoff.component.jsx @@ -16,6 +16,7 @@ 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 { timeTicketClockOutStart } from "../../redux/timetickets/timetickets.actions"; // import { selectCurrentTimeTicketJobId } from "../../redux/timetickets/timetickets.selectors"; //TODO add props needed for call @@ -26,7 +27,9 @@ const mapStateToProps = createStructuredSelector({ currentTmTicketJobId: selectCurrentTmTicketJobId, // currentJobId: selectCurrentTimeTicketJobId }); -// const mapDispatchToProps = (dispatch) => ({}); + const mapDispatchToProps = (dispatch) => ({ + timeTicketClockOutStart + }); export function TimeTicketClockOff({ currentEmployee, diff --git a/redux/timetickets/timetickets.actions.js b/redux/timetickets/timetickets.actions.js index b1bcfd4..3de6263 100644 --- a/redux/timetickets/timetickets.actions.js +++ b/redux/timetickets/timetickets.actions.js @@ -24,3 +24,29 @@ export const timeTicketCreateFailure = (error) => ({ type: TimeTicketsActionTypes.TIME_TICKET_CREATE_FAILURE, payload: error, }); + +export const timeTicketClockInStart = (timeTicket) => ({ + type: TimeTicketsActionTypes.TIME_TICKET_CLOCKIN_START, + payload: timeTicket, +}); +export const timeTicketClockInSuccess = (insertTimeTickets) => ({ + type: TimeTicketsActionTypes.TIME_TICKET_CLOCKIN_SUCCESS, + payload: insertTimeTickets, +}); +export const timeTicketClockInFailure = (error) => ({ + type: TimeTicketsActionTypes.TIME_TICKET_CLOCKIN_FAILURE, + payload: error, +}); + +export const timeTicketClockOutStart = (timeTicket) => ({ + type: TimeTicketsActionTypes.TIME_TICKET_CLOCKOUT_START, + payload: timeTicket, +}); +export const timeTicketClockOutSuccess = (insertTimeTickets) => ({ + type: TimeTicketsActionTypes.TIME_TICKET_CLOCKOUT_SUCCESS, + payload: insertTimeTickets, +}); +export const timeTicketClockOutFailure = (error) => ({ + type: TimeTicketsActionTypes.TIME_TICKET_CLOCKOUT_FAILURE, + payload: error, +}); diff --git a/redux/timetickets/timetickets.reducer.js b/redux/timetickets/timetickets.reducer.js index 075db46..377c355 100644 --- a/redux/timetickets/timetickets.reducer.js +++ b/redux/timetickets/timetickets.reducer.js @@ -6,6 +6,10 @@ const INITIAL_STATE = { timeTicketJob: null, uploadTimeTicketInProgress: false, uploadTimeTicketError: null, + clockingIn: false, + clockingInError: null, + clockingOut: false, + clockingOutError: null, }; const timeTicketsReducer = (state = INITIAL_STATE, action) => { @@ -23,22 +27,41 @@ const timeTicketsReducer = (state = INITIAL_STATE, action) => { timeTicketJob: action.payload }; case TimeTicketsActionTypes.TIME_TICKET_CREATE_START: - return { - ...state, - uploadTimeTicketInProgress: true - }; + return {...state,uploadTimeTicketInProgress: true}; case TimeTicketsActionTypes.TIME_TICKET_CREATE_SUCCESS: - return { - ...state, //TODO add logic here when successful + return {...state, uploadTimeTicketInProgress: false, uploadTimeTicketError: null, }; case TimeTicketsActionTypes.TIME_TICKET_CREATE_FAILURE: - return { - ...state, + return {...state, uploadTimeTicketInProgress: false, uploadTimeTicketError: action.payload, }; + case TimeTicketsActionTypes.TIME_TICKET_CLOCKIN_START: + return {...state,clockingIn: true}; + case TimeTicketsActionTypes.TIME_TICKET_CLOCKIN_SUCCESS: + return {...state, + clockingIn: false, + clockingInError: null, + }; + case TimeTicketsActionTypes.TIME_TICKET_CLOCKIN_FAILURE: + return {...state, + clockingIn: false, + clockingInError: action.payload, + }; + case TimeTicketsActionTypes.TIME_TICKET_CLOCKOUT_START: + return {...state,clockingOut: true}; + case TimeTicketsActionTypes.TIME_TICKET_CLOCKOUT_SUCCESS: + return {...state, + clockingOut: false, + clockingOutError: null, + }; + case TimeTicketsActionTypes.TIME_TICKET_CLOCKOUT_FAILURE: + return {...state, + clockingOut: false, + clockingOutError: action.payload, + }; default: return state; } diff --git a/redux/timetickets/timetickets.sagas.js b/redux/timetickets/timetickets.sagas.js index 6ea8c7f..5c702b6 100644 --- a/redux/timetickets/timetickets.sagas.js +++ b/redux/timetickets/timetickets.sagas.js @@ -1,6 +1,10 @@ import { timeTicketCreateFailure, timeTicketCreateSuccess, + timeTicketClockInSuccess, + timeTicketClockInFailure, + timeTicketClockOutSuccess, + timeTicketClockOutFailure } from "./timetickets.actions"; import TimeTicketsActionTypes from "./timetickets.types"; import { client } from "../../graphql/client"; @@ -67,6 +71,69 @@ export function* insertNewTimeTicket({ payload: { timeTicketInput } }) { } } -export function* timeTicketsSagas() { - yield all([call(onCreateTimeTicketStart)]); +export function* onClockOutStart() { + yield takeLatest(TimeTicketsActionTypes.TIME_TICKET_CLOCKOUT_START,clockOutStart); +} +export function* clockOutStart({ payload: { timeTicketInput } }) { + try { + logImEXEvent("redux_clockOutStart_attempt"); + //console.loging + console.log("Saga, clockOutStart :", timeTicketInput); + // const timeTicket = yield select(selectCurrentTimeTicket); + // const response = yield call(axios.post, "/tech/login", { + // shopid: bodyshop.id, + // employeeid: employeeId, + // 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)); + // } + } catch (error) { + yield put(timeTicketClockOutFailure(error)); + } +} +export function* onClockInStart() { + yield takeLatest(TimeTicketsActionTypes.TIME_TICKET_CLOCKIN_START,clockInStart); +} +export function* clockInStart({ payload: { timeTicketInput } }) { + try { + logImEXEvent("redux_clockInStart_attempt"); + console.log("Saga, clockInStart :", timeTicketInput); + } catch (error) { + yield put(timeTicketClockInFailure(error)); + } +} +export function* timeTicketsSagas() { + yield all([call(onCreateTimeTicketStart),call(onClockOutStart),call(onClockInStart)]); } diff --git a/redux/timetickets/timetickets.types.js b/redux/timetickets/timetickets.types.js index 5737385..db91800 100644 --- a/redux/timetickets/timetickets.types.js +++ b/redux/timetickets/timetickets.types.js @@ -5,5 +5,11 @@ const TimeTicketsActionTypes = { TIME_TICKET_CREATE_START: "TIME_TICKET_CREATE_START", TIME_TICKET_CREATE_SUCCESS: "TIME_TICKET_CREATE_SUCCESS", TIME_TICKET_CREATE_FAILURE: "TIME_TICKET_CREATE_FAILURE", + TIME_TICKET_CLOCKIN_START: "TIME_TICKET_CLOCKIN_START", + TIME_TICKET_CLOCKIN_SUCCESS: "TIME_TICKET_CLOCKIN_SUCCESS", + TIME_TICKET_CLOCKIN_FAILURE: "TIME_TICKET_CLOCKIN_FAILURE", + TIME_TICKET_CLOCKOUT_START: "TIME_TICKET_CLOCKOUT_START", + TIME_TICKET_CLOCKOUT_SUCCESS: "TIME_TICKET_CLOCKOUT_SUCCESS", + TIME_TICKET_CLOCKOUT_FAILURE: "TIME_TICKET_CLOCKOUT_FAILURE", }; export default TimeTicketsActionTypes; From c7959c408050a6ceba637d081eab8b6a73324d16 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 15 May 2023 08:55:45 -0400 Subject: [PATCH 047/105] cleaned up clock out --- .../clockedin-list-item.component.jsx | 88 ++++++++++--------- .../employee-clockedin-list.component.jsx | 22 +++-- redux/timetickets/timetickets.sagas.js | 1 + 3 files changed, 60 insertions(+), 51 deletions(-) diff --git a/components/time-ticket-items/clockedin-list-item.component.jsx b/components/time-ticket-items/clockedin-list-item.component.jsx index 4d92c93..2a699db 100644 --- a/components/time-ticket-items/clockedin-list-item.component.jsx +++ b/components/time-ticket-items/clockedin-list-item.component.jsx @@ -13,34 +13,37 @@ import { logImEXEvent } from "../../firebase/firebase.analytics"; import { employeeSignInStart } from "../../redux/employee/employee.actions"; import { useRef } from "react"; - // const selectNumCompletedTodos = createSelector( // (state) => state.timeTickets, // (timeTickets) => timeTickets.timeTicketJobId // ); //const mapStateToProps = createStructuredSelector({}); - // // setTimeTicketJobId: (jobId) =>dispatch(setTimeTicketJobId({jobId})), - //employeeSignInStart:(idjob) => dispatch(employeeSignInStart(idjob)), +// // setTimeTicketJobId: (jobId) =>dispatch(setTimeTicketJobId({jobId})), +//employeeSignInStart:(idjob) => dispatch(employeeSignInStart(idjob)), const mapDispatchToProps = (dispatch) => ({ - setTmTicketJobId:() => dispatch(setTmTicketJobId(jobId)), + setTmTicketJobId: () => dispatch(setTmTicketJobId({ jobId })), }); -export function ClockedinListItem( props ) { +export function ClockedinListItem( {setTmTicketJobId, ticket }) { + console.log("ClockedinListItem, ticket", ticket); + console.log("ClockedinListItem, setTmTicketJobId", setTmTicketJobId); const { t } = useTranslation(); const navigation = useNavigation(); - console.log("ClockedinListItem, ", props.ticket.job.id); - const jbId = props.ticket.job.id; + + console.log("ClockedinListItem, ticket job id", ticket.job.id); + const jbId = ticket.job.id; console.log("ClockedinListItem, jbId: ", jbId); - const te = useRef(jbId) - let makeNave = (jobId) => ( - console.log("ClockedinListItem ", setTmTicketJobId) - ,console.log("te", jobId) - ,setTmTicketJobId(jobId) - - // ,navigation.navigate("TimeTicketClockOff") - ); + // const te = useRef(jbId); + + const makeNavToTimeTicketClockOff = (jbId,setTmTicketJobId) => ( + console.log("ClockedinListItem, makeNavToTimeTicketClockOff, setTmTicketJobId :", setTmTicketJobId), + console.log("ClockedinListItem, makeNavToTimeTicketClockOff, jobId :", jbId) + //,setTmTicketJobId(jbId) + + ,navigation.navigate("TimeTicketClockOff") + ); // const onPress = (ticket, setCameraJobId) => { // console.log("ClockedinListItem, onPress called"); // console.log("ClockedinListItem, ticket", ticket); @@ -63,24 +66,25 @@ export function ClockedinListItem( props ) { Vehicle : - {`${props.ticket.job.v_model_yr || ""} ${props.ticket.job.v_make_desc || ""} ${ - props.ticket.job.v_model_desc || "" - }`} + {`${ticket.job.v_model_yr || ""} ${ + ticket.job.v_make_desc || "" + } ${ticket.job.v_model_desc || ""}`} - Clocked In : {props.ticket.clockon} + Clocked In :{" "} + {ticket.clockon} Cost Center :{" "} - {props.ticket.cost_center === "timetickets.labels.shift" - ? t(props.ticket.cost_center) - : props.ticket.cost_center} + {ticket.cost_center === "timetickets.labels.shift" + ? t(ticket.cost_center) + : ticket.cost_center} @@ -90,25 +94,25 @@ export function ClockedinListItem( props ) { completedCallback={refetch} /> */} diff --git a/components/time-ticket-lists/employee-clockedin-list.component.jsx b/components/time-ticket-lists/employee-clockedin-list.component.jsx index ec1b2cd..a83cf99 100644 --- a/components/time-ticket-lists/employee-clockedin-list.component.jsx +++ b/components/time-ticket-lists/employee-clockedin-list.component.jsx @@ -11,15 +11,16 @@ import { useQuery } from "@apollo/client"; import { createStructuredSelector } from "reselect"; import { useTranslation } from "react-i18next"; import { ClockedinListItem } from "../time-ticket-items/clockedin-list-item.component"; -import { setTmTicketJobId } from "../../redux/app/app.actions"; + +// import { setTmTicketJobId } from "../../redux/app/app.actions"; const mapStateToProps = createStructuredSelector({ technician: selectTechnician, //currentEmployee: selectCurrentEmployee, }); -const mapDispatchToProps = (dispatch) => ({ - setTmTicketJobId: (jobId) => dispatch(setTmTicketJobId(jobId)), -}); +// const mapDispatchToProps = (dispatch) => ({ +// setTmTicketJobId: (jobId) => dispatch(setTmTicketJobId(jobId)), +// }); export function EmployeeClockedInList({ technician }) { const { t } = useTranslation(); @@ -37,23 +38,26 @@ export function EmployeeClockedInList({ technician }) { ); if (loading) return ; if (error) return ; - //if (error) return ; - console.log("QUERY_ACTIVE_TIME_TICKETS data", data); + + console.log("EmployeeClockedInList, QUERY_ACTIVE_TIME_TICKETS data:", data); // if (data) () => {setTmTicketJobId(data)} + const onRefresh = async () => { return refetch(); }; + return ( {data.timetickets.length > 0 ? ( - You are already clocked in to the following job(s): + You are already clocked in to the following job(s): } - renderItem={(object) => } + renderItem={(object) => } + // setTmTicketJobId={setTmTicketJobId} /> ) : null} @@ -117,4 +121,4 @@ export function EmployeeClockedInList({ technician }) { ); } -export default connect(mapStateToProps, mapDispatchToProps)(EmployeeClockedInList); +export default connect(mapStateToProps, null)(EmployeeClockedInList); diff --git a/redux/timetickets/timetickets.sagas.js b/redux/timetickets/timetickets.sagas.js index 5c702b6..f4de54d 100644 --- a/redux/timetickets/timetickets.sagas.js +++ b/redux/timetickets/timetickets.sagas.js @@ -24,6 +24,7 @@ export function* onCreateTimeTicketStart() { export function* insertNewTimeTicket({ payload: { timeTicketInput } }) { try { logImEXEvent("redux_insertnewtimeticket_attempt"); + console.log("Saga, TIME_TICKET_CREATE_START :", timeTicketInput); //console.loging // console.log("Saga", employeeId, pin, pin); const timeTicket = yield select(selectCurrentTimeTicket); From bc9ef40996c39462d46f25d5af93a79b04037818 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 15 May 2023 10:37:26 -0400 Subject: [PATCH 048/105] ClockOffScrn shows hours by currentTmTicketJobId --- .../time-ticket/screen-time-ticket-clockoff.component.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/time-ticket/screen-time-ticket-clockoff.component.jsx b/components/time-ticket/screen-time-ticket-clockoff.component.jsx index b86fdc5..fe0f769 100644 --- a/components/time-ticket/screen-time-ticket-clockoff.component.jsx +++ b/components/time-ticket/screen-time-ticket-clockoff.component.jsx @@ -37,9 +37,9 @@ export function TimeTicketClockOff({ currentBodyshop, currentTmTicketJobId, }) { - console.log("TimeTicketClockOff, currentEmployee :", currentEmployee); + // console.log("TimeTicketClockOff, currentEmployee :", currentEmployee); //console.log("TimeTicketClockOff, currentRatesNCostCenters :", currentRatesNCostCenters ); - console.log("TimeTicketClockOff, currentBodyshop :", currentBodyshop); + // console.log("TimeTicketClockOff, currentBodyshop :", currentBodyshop); console.log("TimeTicketClockOff, currentTmTicketJobId :", currentTmTicketJobId); // console.log("TimeTicketClockOff, jobId :", jobId); @@ -181,7 +181,7 @@ console.log("TimeTicketClockOff, currentTmTicketJobId :", currentTmTicketJobId);
- +
); From 668d371fb8823b7ac25d7c8d8d9ba584e35ec54a Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 15 May 2023 10:38:06 -0400 Subject: [PATCH 049/105] updated create ticket btn text --- components/time-ticket/screen-time-ticket-create.component.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index 0a19bff..8c93de7 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -144,7 +144,7 @@ export function TimeTicketCreate({ onPress={handleSubmit} title="Submit" > - Save + Create Ticket )} From ccaa0fd450594751731db2a1a20c3561fcd3e75d Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 15 May 2023 10:48:05 -0400 Subject: [PATCH 050/105] cleaned up labor allocations component --- .../labor-allocations-table.component.jsx | 245 +++++++----------- 1 file changed, 88 insertions(+), 157 deletions(-) diff --git a/components/labor-allocations-table/labor-allocations-table.component.jsx b/components/labor-allocations-table/labor-allocations-table.component.jsx index a058c4a..31c3e53 100644 --- a/components/labor-allocations-table/labor-allocations-table.component.jsx +++ b/components/labor-allocations-table/labor-allocations-table.component.jsx @@ -18,55 +18,31 @@ const mapStateToProps = createStructuredSelector({ }); export function LaborAllocationsTable({ jobId, bodyshop, technician }) { - console.log("LaborAllocationsTable, jobId", jobId); - //, loading, refetch - //const jobid = jobid !== undefined ? jobid : ""; + // console.log("LaborAllocationsTable, jobId", jobId); const { t } = useTranslation(); const onRefresh = async () => { - console.log("LaborAllocationsTable refetch"); return refetch(); }; - //maybe use this const { loading, error, data, refetch } = useQuery(GET_LINE_TICKET_BY_PK, { variables: { id: jobId }, skip: !!!jobId, fetchPolicy: "network-only", nextFetchPolicy: "network-only", }); - // console.log("LaborAllocationsTable, data", data); if (error) return ; - // let joblines = []; - // let timetickets = []; - // let adjustments = []; - const [totals, setTotals] = useState([]); - const [state, setState] = useState({ - sortedInfo: { - columnKey: "cost_center", - field: "cost_center", - order: "ascend", - }, - filteredInfo: {}, - }); useEffect(() => { console.log("LaborAllocationsTable useEffect on data change"); - // joblines = data?.joblines ? data.joblines : []; - // timetickets = data?.timetickets ? data.timetickets : []; - // adjustments = data?.adjustments ? data.adjustments : []; }, [data]); useEffect(() => { - console.log( - "LaborAllocationsTable useEffect on [joblines, timetickets, bodyshop, adjustments, jobId] change", - data?.joblines, - data?.adjustments - ); + // console.log("LaborAllocationsTable useEffect on [all inputs] change",data?.joblines,data?.adjustments); if (!!data?.joblines && !!data?.timetickets && !!bodyshop) setTotals( CalculateAllocationsTotals( @@ -79,11 +55,6 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician }) { if (!jobId) setTotals([]); }, [data?.joblines, data?.timetickets, bodyshop, data?.adjustments, jobId]); - // const convertedLines = useMemo( - // () => data?.joblines && data?.joblines.filter((j) => j.convertedtolbr), - // [data?.joblines] - // ); - const summary = totals && totals.reduce( @@ -96,8 +67,7 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician }) { }, { hrs_total: 0, hrs_claimed: 0, adjustments: 0, difference: 0 } ); - - console.log("labor summary is:", summary); + // console.log("labor summary is:", summary); return ( @@ -115,120 +85,70 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician }) { - - } - keyExtractor={(item) => item.cost_center} - ItemSeparatorComponent={} - renderItem={(object) => ( - - - - - {object.item.cost_center} {" ("} - {object.item.mod_lbr_ty}{")"} - - - - {object.item.total && object.item.total.toFixed(1)} - - - {object.item.claimed && object.item.claimed.toFixed(1)} - - - - {object.item.adjustments && object.item.adjustments.toFixed(1)} - {/* {!technician && ( - - - - )} */} - - - - = 0 ? "green" : "red", - }}> - {/* + } + keyExtractor={(item) => item.cost_center} + ItemSeparatorComponent={} + renderItem={(object) => ( + + + + {object.item.cost_center} {" ("} + {object.item.mod_lbr_ty} + {")"} + + + + + {object.item.total && object.item.total.toFixed(1)} + + + + + {object.item.claimed && object.item.claimed.toFixed(1)} + + + + + {object.item.adjustments && + object.item.adjustments.toFixed(1)} + + + + = 0 ? "green" : "red", + color: object.item.difference >= 0 ? "green" : "red", }} > - {_.round(object.difference, 1)} - */} - {_.round(object.item.difference, 1)} - - - + {_.round(object.item.difference, 1)} + + + + )} + /> + {summary && ( + + Totals + + {summary.hrs_total.toFixed(1)} + + + {summary.hrs_claimed.toFixed(1)} + + + {summary.adjustments.toFixed(1)} + + + {summary.difference.toFixed(1)} + + )} - /> - {summary && ( - Totals - {summary.hrs_total.toFixed(1)} - {summary.hrs_claimed.toFixed(1)} - {summary.adjustments.toFixed(1)} - {summary.difference.toFixed(1)} - ) - } ) : null} - {/* - - - {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} - - - )} - /> */} - {/* use "totals" for the rows in the table */} {/* use "summary" for the totals at the bottom */} @@ -236,22 +156,33 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician }) { } const localStyles = StyleSheet.create({ -headerArea:{ - flexDirection:"row", - justifyContent:"center", - alignItems:"center", - margin:1 -}, -footertext:{ - flex:1, textAlign:'center', textAlignVertical:'center',margin:1,paddingBottom:8 -}, -headertext:{ - flex:1, textAlign:'center', textAlignVertical:'center',margin:1,paddingBottom:8 -}, -headertextAdjusts:{ - flex:1, textAlign:'center', textAlignVertical:'center',margin:1,paddingBottom:8 -}, - - + headerArea: { + flexDirection: "row", + justifyContent: "center", + alignItems: "center", + margin: 1, + }, + footertext: { + flex: 1, + textAlign: "center", + textAlignVertical: "center", + margin: 1, + paddingBottom: 8, + }, + headertext: { + flex: 1, + textAlign: "center", + textAlignVertical: "center", + margin: 1, + paddingBottom: 8, + }, + headertextAdjusts: { + flex: 1, + textAlign: "center", + textAlignVertical: "center", + margin: 1, + paddingBottom: 8, + }, }); + export default connect(mapStateToProps, null)(LaborAllocationsTable); From dc798cd92f9896c5bc89772ef2d019f67bbaaf8a Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 15 May 2023 13:57:01 -0400 Subject: [PATCH 051/105] patrick fixed calling wrong export Co-authored-by: Patrick Fic --- .../clockedin-list-item.component.jsx | 28 ++++++++++--------- .../employee-clockedin-list.component.jsx | 12 ++++---- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/components/time-ticket-items/clockedin-list-item.component.jsx b/components/time-ticket-items/clockedin-list-item.component.jsx index 2a699db..fbcb826 100644 --- a/components/time-ticket-items/clockedin-list-item.component.jsx +++ b/components/time-ticket-items/clockedin-list-item.component.jsx @@ -22,10 +22,10 @@ import { useRef } from "react"; //employeeSignInStart:(idjob) => dispatch(employeeSignInStart(idjob)), const mapDispatchToProps = (dispatch) => ({ - setTmTicketJobId: () => dispatch(setTmTicketJobId({ jobId })), + setTmTicketJobIdRedux: (jobId) => dispatch(setTmTicketJobId(jobId)), }); -export function ClockedinListItem( {setTmTicketJobId, ticket }) { +export function ClockedinListItem({ setTmTicketJobIdRedux, ticket }) { console.log("ClockedinListItem, ticket", ticket); console.log("ClockedinListItem, setTmTicketJobId", setTmTicketJobId); @@ -37,12 +37,15 @@ export function ClockedinListItem( {setTmTicketJobId, ticket }) { console.log("ClockedinListItem, jbId: ", jbId); // const te = useRef(jbId); - const makeNavToTimeTicketClockOff = (jbId,setTmTicketJobId) => ( - console.log("ClockedinListItem, makeNavToTimeTicketClockOff, setTmTicketJobId :", setTmTicketJobId), - console.log("ClockedinListItem, makeNavToTimeTicketClockOff, jobId :", jbId) - //,setTmTicketJobId(jbId) - - ,navigation.navigate("TimeTicketClockOff") + const makeNavToTimeTicketClockOff = () => ( + console.log( + "*** THIS IS THE ONE WE ARE TESTING. ClockedinListItem, makeNavToTimeTicketClockOff, setTmTicketJobId :", + setTmTicketJobIdRedux + ), + //console.log("ClockedinListItem, makeNavToTimeTicketClockOff, jobId :", jbId) + setTmTicketJobIdRedux(ticket.job.id), + //, + navigation.navigate("TimeTicketClockOff") ); // const onPress = (ticket, setCameraJobId) => { // console.log("ClockedinListItem, onPress called"); @@ -72,13 +75,12 @@ export function ClockedinListItem( {setTmTicketJobId, ticket }) { Vehicle : - {`${ticket.job.v_model_yr || ""} ${ - ticket.job.v_make_desc || "" - } ${ticket.job.v_model_desc || ""}`} + {`${ticket.job.v_model_yr || ""} ${ticket.job.v_make_desc || ""} ${ + ticket.job.v_model_desc || "" + }`} - Clocked In :{" "} - {ticket.clockon} + Clocked In : {ticket.clockon} Cost Center :{" "} diff --git a/components/time-ticket-lists/employee-clockedin-list.component.jsx b/components/time-ticket-lists/employee-clockedin-list.component.jsx index a83cf99..2d375a0 100644 --- a/components/time-ticket-lists/employee-clockedin-list.component.jsx +++ b/components/time-ticket-lists/employee-clockedin-list.component.jsx @@ -10,7 +10,7 @@ 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"; +import ClockedinListItem from "../time-ticket-items/clockedin-list-item.component"; // import { setTmTicketJobId } from "../../redux/app/app.actions"; @@ -38,9 +38,9 @@ export function EmployeeClockedInList({ technician }) { ); if (loading) return ; if (error) return ; - + console.log("EmployeeClockedInList, QUERY_ACTIVE_TIME_TICKETS data:", data); -// if (data) () => {setTmTicketJobId(data)} + // if (data) () => {setTmTicketJobId(data)} const onRefresh = async () => { return refetch(); @@ -50,13 +50,15 @@ export function EmployeeClockedInList({ technician }) { {data.timetickets.length > 0 ? ( - You are already clocked in to the following job(s): + + You are already clocked in to the following job(s): + } - renderItem={(object) => } + renderItem={(object) => } // setTmTicketJobId={setTmTicketJobId} /> From d860626875c41cb28f6af3e8009048b8750bfcf0 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 15 May 2023 13:57:45 -0400 Subject: [PATCH 052/105] cleaning up some files --- components/Selects/select-job-name.jsx | 3 +++ .../labor-allocations-table-container.component.jsx | 12 ++++-------- .../screen-time-ticket-clockoff.component.jsx | 3 --- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/components/Selects/select-job-name.jsx b/components/Selects/select-job-name.jsx index 6b0655b..8ef7f6a 100644 --- a/components/Selects/select-job-name.jsx +++ b/components/Selects/select-job-name.jsx @@ -12,6 +12,9 @@ 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 not currently used + export function JobSearchSelect( convertedOnly = false, notInvoiced = false, diff --git a/components/labor-allocations-table/labor-allocations-table-container.component.jsx b/components/labor-allocations-table/labor-allocations-table-container.component.jsx index 481caef..ff85fe4 100644 --- a/components/labor-allocations-table/labor-allocations-table-container.component.jsx +++ b/components/labor-allocations-table/labor-allocations-table-container.component.jsx @@ -1,15 +1,13 @@ 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 { StyleSheet, View } from "react-native"; 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); - + // console.log("LaborAllocationsTableContainer, jobId", jobId); const { t } = useTranslation(); const { loading, error, data, refetch } = useQuery(GET_LINE_TICKET_BY_PK, { @@ -18,8 +16,7 @@ export function LaborAllocationsTableContainer({ jobId }) { fetchPolicy: "network-only", nextFetchPolicy: "network-only", }); - - console.log("LaborAllocationsTableContainer, data", data); + // console.log("LaborAllocationsTableContainer, data", data); if (error) return ; return ( @@ -34,8 +31,7 @@ export function LaborAllocationsTableContainer({ jobId }) { adjustments={data ? data.jobs_by_pk.lbr_adjustments : []} /> ) : null} - - + ); } diff --git a/components/time-ticket/screen-time-ticket-clockoff.component.jsx b/components/time-ticket/screen-time-ticket-clockoff.component.jsx index fe0f769..d824096 100644 --- a/components/time-ticket/screen-time-ticket-clockoff.component.jsx +++ b/components/time-ticket/screen-time-ticket-clockoff.component.jsx @@ -45,9 +45,6 @@ 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); From b9cb922a39bc9e3d3e4c66c61b22a9a7f8ec935e Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 15 May 2023 17:08:58 -0400 Subject: [PATCH 053/105] removed console logs --- util/labor-allocations-table.utility.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/util/labor-allocations-table.utility.js b/util/labor-allocations-table.utility.js index 30deccd..a2c4f88 100644 --- a/util/labor-allocations-table.utility.js +++ b/util/labor-allocations-table.utility.js @@ -13,17 +13,17 @@ export const CalculateAllocationsTotals = ( // console.log("🚀 ~ file: timetickets", timetickets); const responsibilitycenters = bodyshop.md_responsibility_centers; const jobCodes = joblines.map((item) => item.mod_lbr_ty); - console.log("jobCodes :", jobCodes); + // console.log("jobCodes :", jobCodes); //.filter((value, index, self) => self.indexOf(value) === index && !!value); const ticketCodes = timetickets.map((item) => item.ciecacode); - console.log("ticketCodes :", ticketCodes); + // console.log("ticketCodes :", ticketCodes); //.filter((value, index, self) => self.indexOf(value) === index && !!value); const adjustmentCodes = Object.keys(adjustments); - console.log("adjustmentCodes :", adjustmentCodes); + // console.log("adjustmentCodes :", adjustmentCodes); const allCodes = [...jobCodes, ...ticketCodes, ...adjustmentCodes].filter( (value, index, self) => self.indexOf(value) === index && !!value ); - console.log("allCodes :", allCodes); + // console.log("allCodes :", allCodes); const r = allCodes.reduce((acc, value) => { const r = { @@ -48,7 +48,7 @@ export const CalculateAllocationsTotals = ( acc.push(r); return acc; }, []); - console.log(" r is :", r); + //console.log(" r is :", r); return r; }; From b13e84b8e1730d6849c09b87fc69b741c8ec63e2 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 15 May 2023 17:09:50 -0400 Subject: [PATCH 054/105] clean up of files --- .../clockedin-list-item.component.jsx | 109 ++---------------- .../screen-time-ticket-clockoff.component.jsx | 72 +++++++++++- 2 files changed, 77 insertions(+), 104 deletions(-) diff --git a/components/time-ticket-items/clockedin-list-item.component.jsx b/components/time-ticket-items/clockedin-list-item.component.jsx index fbcb826..d46d08e 100644 --- a/components/time-ticket-items/clockedin-list-item.component.jsx +++ b/components/time-ticket-items/clockedin-list-item.component.jsx @@ -1,69 +1,29 @@ -import { Ionicons } from "@expo/vector-icons"; import { useNavigation } from "@react-navigation/native"; import React from "react"; import { useTranslation } from "react-i18next"; import { Button, Card, Text } from "react-native-paper"; -import { connect, useSelector, useDispatch } from "react-redux"; -import { createSelector, createStructuredSelector } from "reselect"; +import { connect } from "react-redux"; import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component"; import { DateTimeFormatter } from "../../util/DateFormater"; -// import { setTimeTicketJobId } from "../../redux/timetickets/timetickets.actions"; import { setTmTicketJobId } from "../../redux/app/app.actions"; -import { logImEXEvent } from "../../firebase/firebase.analytics"; -import { employeeSignInStart } from "../../redux/employee/employee.actions"; -import { useRef } from "react"; - -// const selectNumCompletedTodos = createSelector( -// (state) => state.timeTickets, -// (timeTickets) => timeTickets.timeTicketJobId -// ); -//const mapStateToProps = createStructuredSelector({}); -// // setTimeTicketJobId: (jobId) =>dispatch(setTimeTicketJobId({jobId})), -//employeeSignInStart:(idjob) => dispatch(employeeSignInStart(idjob)), const mapDispatchToProps = (dispatch) => ({ setTmTicketJobIdRedux: (jobId) => dispatch(setTmTicketJobId(jobId)), }); export function ClockedinListItem({ setTmTicketJobIdRedux, ticket }) { - console.log("ClockedinListItem, ticket", ticket); - console.log("ClockedinListItem, setTmTicketJobId", setTmTicketJobId); - const { t } = useTranslation(); const navigation = useNavigation(); - console.log("ClockedinListItem, ticket job id", ticket.job.id); - const jbId = ticket.job.id; - console.log("ClockedinListItem, jbId: ", jbId); - // const te = useRef(jbId); - const makeNavToTimeTicketClockOff = () => ( - console.log( - "*** THIS IS THE ONE WE ARE TESTING. ClockedinListItem, makeNavToTimeTicketClockOff, setTmTicketJobId :", - setTmTicketJobIdRedux - ), - //console.log("ClockedinListItem, makeNavToTimeTicketClockOff, jobId :", jbId) + // console.log("makeNavToTimeTicketClockOff, checkHasDispatchCall:",setTmTicketJobIdRedux), setTmTicketJobIdRedux(ticket.job.id), - //, - navigation.navigate("TimeTicketClockOff") + navigation.navigate("TimeTicketClockOff", { + // jobId: ticket.jobid, //item.id, + timeTicketId:ticket.id, + //completedCallback: refetch, + }) ); - // 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 ( @@ -90,64 +50,11 @@ export function ClockedinListItem({ setTmTicketJobIdRedux, ticket }) { - {/* */} - - // {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 }) => ( - // - // )} - // /> ); } diff --git a/components/time-ticket/screen-time-ticket-clockoff.component.jsx b/components/time-ticket/screen-time-ticket-clockoff.component.jsx index d824096..cd0bd41 100644 --- a/components/time-ticket/screen-time-ticket-clockoff.component.jsx +++ b/components/time-ticket/screen-time-ticket-clockoff.component.jsx @@ -17,6 +17,7 @@ import { useMutation } from "@apollo/client"; import { selectCurrentTmTicketJobId } from "../../redux/app/app.selectors"; import ErrorDisplay from "../error-display/error-display.component"; import { timeTicketClockOutStart } from "../../redux/timetickets/timetickets.actions"; +import { logImEXEvent } from "../../firebase/firebase.analytics"; // import { selectCurrentTimeTicketJobId } from "../../redux/timetickets/timetickets.selectors"; //TODO add props needed for call @@ -25,6 +26,8 @@ const mapStateToProps = createStructuredSelector({ currentRatesNCostCenters: selectRates, currentBodyshop: selectBodyshop, currentTmTicketJobId: selectCurrentTmTicketJobId, + + //add way to get timeTicketId // currentJobId: selectCurrentTimeTicketJobId }); const mapDispatchToProps = (dispatch) => ({ @@ -36,8 +39,10 @@ export function TimeTicketClockOff({ currentRatesNCostCenters, currentBodyshop, currentTmTicketJobId, + route, }) { - // console.log("TimeTicketClockOff, currentEmployee :", currentEmployee); + const { timeTicketId } = route.params; + console.log("TimeTicketClockOff, timeTicketId :", timeTicketId); //console.log("TimeTicketClockOff, currentRatesNCostCenters :", currentRatesNCostCenters ); // console.log("TimeTicketClockOff, currentBodyshop :", currentBodyshop); @@ -75,6 +80,67 @@ console.log("TimeTicketClockOff, currentTmTicketJobId :", currentTmTicketJobId); //TODO update with start call for create time ticket }; + + + const [updateTimeticket] = useMutation(UPDATE_TIME_TICKET); + + + + const handleFinish = async (values) => { + logImEXEvent("TimeTicketClockOff_handleFinish"); + + //build obj + const tempcallobj = { + variables: { + timeticketId: timeTicketId, + timeticket: { + clockoff: (await axios.post("/utils/time")).data, + ...values, + rate: + emps && + emps.rates.filter((r) => r.cost_center === values.cost_center)[0] + ?.rate, + flat_rate: emps && emps.flat_rate, + 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("TimeTicketClockOff, tempcallobj :",tempcallobj); + +//after obj is good add below to make call + //setLoading(true); + //const result = await updateTimeticket(); + + +//after call results are retuning add handling below for cases + + // 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 handleFinish = async (values) => { // //logImEXEvent("tech_clock_out_job"); @@ -135,7 +201,7 @@ console.log("TimeTicketClockOff, currentTmTicketJobId :", currentTmTicketJobId); productivehours: "", actualhours: "", }} - onSubmit={formSubmit} + onSubmit={handleFinish} > {({ handleChange, handleBlur, handleSubmit, values }) => ( @@ -168,7 +234,7 @@ console.log("TimeTicketClockOff, currentTmTicketJobId :", currentTmTicketJobId); /> - ); -} -export default connect(null, mapDispatchToProps)(SignOutButton); diff --git a/components/labor-allocations-table/labor-allocations-table.component.jsx b/components/labor-allocations-table/labor-allocations-table.component.jsx index 31c3e53..b9d9ba1 100644 --- a/components/labor-allocations-table/labor-allocations-table.component.jsx +++ b/components/labor-allocations-table/labor-allocations-table.component.jsx @@ -38,7 +38,7 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician }) { const [totals, setTotals] = useState([]); useEffect(() => { - console.log("LaborAllocationsTable useEffect on data change"); + // console.log("LaborAllocationsTable useEffect on data change"); }, [data]); useEffect(() => { diff --git a/components/time-ticket/screen-time-ticket-clockoff.component.jsx b/components/time-ticket/screen-time-ticket-clockoff.component.jsx index cd0bd41..4505f11 100644 --- a/components/time-ticket/screen-time-ticket-clockoff.component.jsx +++ b/components/time-ticket/screen-time-ticket-clockoff.component.jsx @@ -1,5 +1,5 @@ import { Formik } from "formik"; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { StyleSheet, Text, View, ScrollView } from "react-native"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; @@ -18,6 +18,8 @@ import { selectCurrentTmTicketJobId } from "../../redux/app/app.selectors"; import ErrorDisplay from "../error-display/error-display.component"; import { timeTicketClockOutStart } from "../../redux/timetickets/timetickets.actions"; import { logImEXEvent } from "../../firebase/firebase.analytics"; +import axios from "axios"; +import { useNavigation } from "@react-navigation/native"; // import { selectCurrentTimeTicketJobId } from "../../redux/timetickets/timetickets.selectors"; //TODO add props needed for call @@ -26,13 +28,10 @@ const mapStateToProps = createStructuredSelector({ currentRatesNCostCenters: selectRates, currentBodyshop: selectBodyshop, currentTmTicketJobId: selectCurrentTmTicketJobId, - - //add way to get timeTicketId -// currentJobId: selectCurrentTimeTicketJobId }); - const mapDispatchToProps = (dispatch) => ({ - timeTicketClockOutStart - }); +const mapDispatchToProps = (dispatch) => ({ + timeTicketClockOutStart, +}); export function TimeTicketClockOff({ currentEmployee, @@ -41,157 +40,84 @@ export function TimeTicketClockOff({ currentTmTicketJobId, route, }) { + const navigation = useNavigation(); const { timeTicketId } = route.params; - console.log("TimeTicketClockOff, timeTicketId :", timeTicketId); - //console.log("TimeTicketClockOff, currentRatesNCostCenters :", currentRatesNCostCenters ); - // console.log("TimeTicketClockOff, currentBodyshop :", currentBodyshop); + // console.log("TimeTicketClockOff, timeTicketId :", timeTicketId); + // console.log( "TimeTicketClockOff, currentTmTicketJobId :", currentTmTicketJobId ); -console.log("TimeTicketClockOff, currentTmTicketJobId :", currentTmTicketJobId); -// console.log("TimeTicketClockOff, jobId :", jobId); -// console.log("TimeTicketClockOff, timeTicketId :", timeTicketId); const { t } = useTranslation(); const [loading, setLoading] = useState(false); - + const [error, setError] = useState(null); 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 [updateTimeticket] = useMutation(UPDATE_TIME_TICKET); - - const handleFinish = async (values) => { logImEXEvent("TimeTicketClockOff_handleFinish"); + // console.log("TimeTicketClockOff, values.cost_center?.value :", currentSCC); - //build obj + if ( + !!values.actualhours && + !!values.productivehours && + !!currentSCC?.value + ) { + setError(null); + console.log("all have values:"); + } else { + console.log("missing values!"); + setError({ message: "Please make sure all fields have a value." }); + } const tempcallobj = { variables: { timeticketId: timeTicketId, timeticket: { - clockoff: (await axios.post("/utils/time")).data, - ...values, - rate: - emps && - emps.rates.filter((r) => r.cost_center === values.cost_center)[0] - ?.rate, - flat_rate: emps && emps.flat_rate, + actualhrs: values?.actualhours, ciecacode: - bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber - ? values.cost_center + currentBodyshop?.cdk_dealerid || currentBodyshop?.pbs_serialnumber + ? currentSCC?.value : Object.keys( - bodyshop.md_responsibility_centers.defaults.costs + currentBodyshop.md_responsibility_centers.defaults.costs ).find((key) => { return ( - bodyshop.md_responsibility_centers.defaults.costs[key] === - values.cost_center + currentBodyshop.md_responsibility_centers.defaults.costs[ + key + ] === currentSCC?.value ); }), + clockoff: (await axios.post("/utils/time")).data, + cost_center: currentSCC?.value, + flat_rate: + currentEmployee && + currentEmployee.technician && + currentEmployee.technician?.flat_rate, + productivehrs: values?.productivehours, + rate: + currentRatesNCostCenters && + currentSCC?.value && + currentRatesNCostCenters.filter( + (r) => r.cost_center === currentSCC?.value + )[0]?.rate, }, }, }; + // console.log("TimeTicketClockOff, tempcallobj :", tempcallobj); - console.log("TimeTicketClockOff, tempcallobj :",tempcallobj); + //after obj is good add below to make call + setLoading(true); + const result = await updateTimeticket(tempcallobj); -//after obj is good add below to make call - //setLoading(true); - //const result = await updateTimeticket(); - - -//after call results are retuning add handling below for cases - - // if (!!result.errors) { - // notification["error"]({ - // message: t("timetickets.errors.clockingout", { - // message: JSON.stringify(result.errors), - // }), - // }); - // } else { - // notification["success"]({ - // message: t("timetickets.successes.clockedout"), - // }); - // } + //after call results are retuning add handling below for cases + // console.log("updateTimeticket, result :", result); setLoading(false); - // if (completedCallback) completedCallback(); - }; - - -// 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(); -// }; - + if (!!result.errors) { + // console.log("updateTimeticket, result.error :", result.errors); + setError(SON.stringify(result.errors)); + } else { + console.log("updateTimeticket, result. :", result.data); + navigation.goBack(); + } + //if (completedCallback) completedCallback(); + }; return ( @@ -205,12 +131,6 @@ console.log("TimeTicketClockOff, currentTmTicketJobId :", currentTmTicketJobId); > {({ handleChange, handleBlur, handleSubmit, values }) => ( - {/* */} + {error ? : null} )} From 3da64effa8264b0b543196af4674aa65217f56ec Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Tue, 16 May 2023 00:33:39 -0400 Subject: [PATCH 056/105] add grab vals,call INSERT_NEW_TIME_TICKET, nav back --- components/error-display/error-display.component.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/error-display/error-display.component.jsx b/components/error-display/error-display.component.jsx index 84f41b6..a527810 100644 --- a/components/error-display/error-display.component.jsx +++ b/components/error-display/error-display.component.jsx @@ -3,7 +3,7 @@ import { View, Text } from "react-native"; export default function ErrorDisplay({ errorMessage }) { return ( - + {errorMessage} ); From 9132c1bb9b147ad8929926d5a0f86c4bd595596c Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Tue, 16 May 2023 00:33:55 -0400 Subject: [PATCH 057/105] added nav --- .../screen-time-ticket-create.component.jsx | 126 ++++++++++++++++-- 1 file changed, 115 insertions(+), 11 deletions(-) diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index 8c93de7..a27d3e8 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -18,6 +18,12 @@ import { useCallback } from "react"; import LaborAllocationsTable from "../labor-allocations-table/labor-allocations-table.component"; import ErrorDisplay from "../error-display/error-display.component"; +import { INSERT_NEW_TIME_TICKET } from "../../graphql/timetickets.queries"; +import { useMutation } from "@apollo/client"; +import axios from "axios"; +import { logImEXEvent } from "../../firebase/firebase.analytics"; +import moment from "moment"; +import { useNavigation } from "@react-navigation/native"; //TODO add props needed for call const mapStateToProps = createStructuredSelector({ @@ -32,7 +38,10 @@ export function TimeTicketCreate({ currentRatesNCostCenters, currentBodyshop, }) { + const navigation = useNavigation(); const { t } = useTranslation(); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); const [isDatePickerVisible, setDatePickerVisibility] = useState(false); const [date2, setDate2] = useState(new Date()); @@ -41,6 +50,7 @@ export function TimeTicketCreate({ // const [currentSJob, setCurrentSJob] = useState(null); const [currentSJobId, setCurrentSJobId] = useState(null); + // const wrapperSetCurrentSJobState = useCallback( // (val) => { // setCurrentSJob(val); @@ -59,10 +69,106 @@ export function TimeTicketCreate({ //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 [insertTimeTicket] = useMutation(INSERT_NEW_TIME_TICKET); + + const handleFinish = async (values) => { + const theTime = (await axios.post("/utils/time")).data; + setLoading(true); + + logImEXEvent("insertTimeTicket_handleFinish"); + // console.log("insertTimeTicket, currentSCC :", currentSCC); + // console.log("insertTimeTicket, currentSCC :", currentSJobId); + // console.log("insertTimeTicket, values :", values); + + if ( + !!currentSCC?.value && + !!currentSJobId?.value && + !!values.productivehours && + !!values.actualhours && + !!values.productivehours + ) { + setError(null); + console.log("all have values:"); + } else { + console.log("missing values!"); + setError({ message: "Please make sure all fields have a value." }); + return; + } + + if (currentSJobId) + console.log("jobid or currentSJobId", currentSJobId?.value); + + const tempVariablesObj = { + variables: { + timeTicketInput: [ + { + bodyshopid: currentBodyshop.id, + employeeid: currentEmployee?.technician?.id, + date: moment(theTime).format("YYYY-MM-DD"), + clockon: moment(theTime), + jobid: currentSJobId?.value, + cost_center: currentSCC?.value, + 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); + }), + } + ], + }, + }; + // const tempcallobj = { + // variables: { + // timeticketId: timeTicketId, + // timeticket: { + // actualhrs: values?.actualhours, + // 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 + // ); + // }), + // clockoff: (await axios.post("/utils/time")).data, + // cost_center: currentSCC?.value, + // flat_rate: + // currentEmployee && + // currentEmployee.technician && + // currentEmployee.technician?.flat_rate, + // productivehrs: values?.productivehours, + // rate: + // currentRatesNCostCenters && + // currentSCC?.value && + // currentRatesNCostCenters.filter( + // (r) => r.cost_center === currentSCC?.value + // )[0]?.rate, + // }, + // }, + // }; + console.log("insertTimeTicket, tempVariablesObj :", tempVariablesObj?.variables?.timeTicketInput[0]); + + //after obj is good add below to make call + + const result = await insertTimeTicket(tempVariablesObj); + + //after call results are retuning add handling below for cases + console.log("insertTimeTicket, result :", result); + setLoading(false); + + if (!!result.errors) { + console.log("insertTimeTicket, result.error :", result.errors); + setError(SON.stringify(result.errors)); + } else { + console.log("insertTimeTicket, result. :", result.data); + navigation.goBack(); + } + // if (completedCallback) completedCallback(); }; return ( @@ -70,14 +176,14 @@ export function TimeTicketCreate({ {({ handleChange, handleBlur, handleSubmit, values }) => ( @@ -146,17 +252,15 @@ export function TimeTicketCreate({ > Create Ticket + {error ? : null} )} {/* Below is for list of jobs/tickets */} - - - - +
); From e950fd9fd7db3f6bd2d1872193f610c9c9eaa01c Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Tue, 16 May 2023 13:49:28 -0400 Subject: [PATCH 058/105] Add working call for clock in to timeticketbrowser --- .../screen-time-ticket-browser.component.jsx | 159 +++++++++--------- .../employee-clockedin-list.component.jsx | 7 +- .../screen-time-ticket-clockoff.component.jsx | 1 - .../screen-time-ticket-create.component.jsx | 102 ++++------- graphql/bodyshop.queries.js | 1 - 5 files changed, 124 insertions(+), 146 deletions(-) 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 97d2bea..c784138 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,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from "react"; +import React, { useState } from "react"; import { View, Text } from "react-native"; import axios from "axios"; import { connect } from "react-redux"; @@ -26,6 +26,10 @@ import moment from "moment"; import { EmployeeClockedInList } from "../time-ticket-lists/employee-clockedin-list.component"; import { useNavigation } from "@react-navigation/native"; +import { INSERT_NEW_TIME_TICKET } from "../../graphql/timetickets.queries"; +import { useMutation } from "@apollo/client"; +import { logImEXEvent } from "../../firebase/firebase.analytics"; + const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, loaderGettingRates: selectGettingRates, @@ -54,9 +58,12 @@ export function ScreenTimeTicketBrowser({ const navigation = useNavigation(); //const employeeId = currentEmployee.technician.id; const [currentSCC, setCurrentSCC] = useState(null); - // const [currentSJob, setCurrentSJob] = useState(null); const [currentSJobId, setCurrentSJobId] = useState(null); - + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [insertTimeTicket] = useMutation(INSERT_NEW_TIME_TICKET, { + refetchQueries: ["QUERY_ACTIVE_TIME_TICKETS"], + }); // const { error, data } = useQuery(QUERY_EMPLOYEE_BY_ID, { // variables: { id: currentEmployee.technician.id }, // }); @@ -69,78 +76,81 @@ export function ScreenTimeTicketBrowser({ // }, // [setCurrentSJobId] // ); + const handleFinish = async (values) => { + console.log("handleFinish called in ScreenTimeTicketBrowser"); + setLoading(true); + setError(null); + //do stuff... - const getRates = (currentEmployee) => { - employeeGetRatesStart(currentEmployee.technician.id); - }; - const createTheTimeTicketOBJ = async ( - currentEmployee, - currentBodyshop, - currentSCC, - currentSJobId - ) => { 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: [ - // { - //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, - //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); - // }), - //have flat_rate: currentEmployee.technician.flat_rate, - //have rate: 1, - // }, - // ], - // }; - // console.log(temp); - //employeeGetRatesStart(currentEmployee.technician.id); + if (!!currentSCC?.value && !!currentSJobId?.value) { + setError(null); + console.log("have all values"); + } else { + console.log("missing values!"); + setLoading(false); + setError({ message: "Please make sure all fields have a value." }); + return; + } + + if (currentSJobId) + console.log("jobid or currentSJobId", currentSJobId?.value); + + + const tempVariablesObj = { + variables: { + timeTicketInput: [ + { + bodyshopid: currentBodyshop.id, + employeeid: currentEmployee?.technician?.id, + date: moment(theTime).format("YYYY-MM-DD"), + clockon: moment(theTime), + jobid: currentSJobId?.value, + cost_center: currentSCC?.value, + 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 + ); + }), + }, + ], + }, + }; + console.info( + "INSERT_NEW_TIME_TICKET, variables for clockin. : ", + tempVariablesObj?.variables?.timeTicketInput[0] + ); + + + const result = await insertTimeTicket(tempVariablesObj); + console.log("insertTimeTicket, result :", result); + + if (!!result.errors) { + console.log("insertTimeTicket, result.error :", result.errors); + setError(JSON.stringify(result.errors)); + } else { + console.log("insertTimeTicket, result. :", result.data); + //show success + //clear fields + + setCurrentSJobId(null); + setCurrentSCC(null); + } + + + setLoading(false); }; + return ( - - {/* */} - {/* {signingErrorMsg} */} + - + {error && error?.message ? ( + + ) : null} diff --git a/components/time-ticket-lists/employee-clockedin-list.component.jsx b/components/time-ticket-lists/employee-clockedin-list.component.jsx index 2d375a0..9a1b86d 100644 --- a/components/time-ticket-lists/employee-clockedin-list.component.jsx +++ b/components/time-ticket-lists/employee-clockedin-list.component.jsx @@ -23,6 +23,8 @@ const mapStateToProps = createStructuredSelector({ // }); export function EmployeeClockedInList({ technician }) { + console.info("EmployeeClockedInList, QUERY_ACTIVE_TIME_TICKETS called."); + const { t } = useTranslation(); const { loading, error, data, refetch } = useQuery( @@ -39,15 +41,12 @@ export function EmployeeClockedInList({ technician }) { if (loading) return ; if (error) return ; - console.log("EmployeeClockedInList, QUERY_ACTIVE_TIME_TICKETS data:", data); - // if (data) () => {setTmTicketJobId(data)} - const onRefresh = async () => { return refetch(); }; return ( - + {data.timetickets.length > 0 ? ( diff --git a/components/time-ticket/screen-time-ticket-clockoff.component.jsx b/components/time-ticket/screen-time-ticket-clockoff.component.jsx index 4505f11..1487ddd 100644 --- a/components/time-ticket/screen-time-ticket-clockoff.component.jsx +++ b/components/time-ticket/screen-time-ticket-clockoff.component.jsx @@ -22,7 +22,6 @@ import axios from "axios"; import { useNavigation } from "@react-navigation/native"; // import { selectCurrentTimeTicketJobId } from "../../redux/timetickets/timetickets.selectors"; -//TODO add props needed for call const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, currentRatesNCostCenters: selectRates, diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index a27d3e8..feab9b3 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -1,5 +1,5 @@ import { Formik } from "formik"; -import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import { StyleSheet, Text, View, ScrollView } from "react-native"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; @@ -50,7 +50,6 @@ export function TimeTicketCreate({ // const [currentSJob, setCurrentSJob] = useState(null); const [currentSJobId, setCurrentSJobId] = useState(null); - // const wrapperSetCurrentSJobState = useCallback( // (val) => { // setCurrentSJob(val); @@ -70,13 +69,14 @@ export function TimeTicketCreate({ hideDatePicker(); }; - const [insertTimeTicket] = useMutation(INSERT_NEW_TIME_TICKET); + const [insertTicket] = useMutation(INSERT_NEW_TIME_TICKET); const handleFinish = async (values) => { - const theTime = (await axios.post("/utils/time")).data; + logImEXEvent("handleFinish_called_in_TimeTicketCreate"); + console.log("handleFinish called in TimeTicketCreate"); + setError(null); setLoading(true); - logImEXEvent("insertTimeTicket_handleFinish"); // console.log("insertTimeTicket, currentSCC :", currentSCC); // console.log("insertTimeTicket, currentSCC :", currentSJobId); // console.log("insertTimeTicket, values :", values); @@ -85,89 +85,60 @@ export function TimeTicketCreate({ !!currentSCC?.value && !!currentSJobId?.value && !!values.productivehours && - !!values.actualhours && - !!values.productivehours + !!currentBodyshop.id && + !!currentEmployee?.technician?.id && + !!date2 ) { setError(null); - console.log("all have values:"); + console.log("have all values"); } else { console.log("missing values!"); + setLoading(false); setError({ message: "Please make sure all fields have a value." }); return; } - if (currentSJobId) - console.log("jobid or currentSJobId", currentSJobId?.value); - + if (date2) console.log("rate :", currentRatesNCostCenters && currentSCC?.value ? currentRatesNCostCenters.filter((r) => r.cost_center === currentSCC?.value)[0].rate : null);//2023-05-16T16:45:27.154Z + if (date2) console.log("bodyshopid : ", currentBodyshop.id); + if (date2) console.log("moment(date2).format(YYYY-MM-DD)", moment(date2).format("YYYY-MM-DD")); const tempVariablesObj = { variables: { timeTicketInput: [ { + actualhrs: values?.actualhours ? values?.actualhours : null, bodyshopid: currentBodyshop.id, - employeeid: currentEmployee?.technician?.id, - date: moment(theTime).format("YYYY-MM-DD"), - clockon: moment(theTime), - jobid: currentSJobId?.value, + 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);}), cost_center: currentSCC?.value, - 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); - }), - } + date: moment(date2).format("YYYY-MM-DD"), + employeeid: currentEmployee?.technician?.id, + flat_rate: currentEmployee && currentEmployee.technician && currentEmployee.technician?.flat_rate, + jobid: currentSJobId?.value, + productivehrs: values?.productivehours, + rate: currentRatesNCostCenters && currentSCC?.value ? currentRatesNCostCenters.filter((r) => r.cost_center === currentSCC?.value)[0].rate : null, + }, ], }, }; - // const tempcallobj = { - // variables: { - // timeticketId: timeTicketId, - // timeticket: { - // actualhrs: values?.actualhours, - // 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 - // ); - // }), - // clockoff: (await axios.post("/utils/time")).data, - // cost_center: currentSCC?.value, - // flat_rate: - // currentEmployee && - // currentEmployee.technician && - // currentEmployee.technician?.flat_rate, - // productivehrs: values?.productivehours, - // rate: - // currentRatesNCostCenters && - // currentSCC?.value && - // currentRatesNCostCenters.filter( - // (r) => r.cost_center === currentSCC?.value - // )[0]?.rate, - // }, - // }, - // }; - console.log("insertTimeTicket, tempVariablesObj :", tempVariablesObj?.variables?.timeTicketInput[0]); + // clockoff: undefined, + // clockon: undefined, + // memo: undefined, + + console.log("insertTimeTicket, tempVariablesObj. :", tempVariablesObj?.variables?.timeTicketInput[0]); //after obj is good add below to make call - const result = await insertTimeTicket(tempVariablesObj); + const result = await insertTicket(tempVariablesObj); - //after call results are retuning add handling below for cases + // //after call results are retuning add handling below for cases console.log("insertTimeTicket, result :", result); setLoading(false); - - if (!!result.errors) { - console.log("insertTimeTicket, result.error :", result.errors); - setError(SON.stringify(result.errors)); - } else { - console.log("insertTimeTicket, result. :", result.data); - navigation.goBack(); - } + // if (!!result.errors) { + // console.log("insertTimeTicket, result.error :", result.errors); + // setError(JSON.stringify(result.errors)); + // } else { + // console.log("insertTimeTicket, result. :", result.data); + // navigation.goBack(); + // } // if (completedCallback) completedCallback(); }; @@ -248,6 +219,7 @@ export function TimeTicketCreate({ - {error && error?.message ? ( - - ) : null} - - + + + + + + + {error && error?.message ? ( + + ) : null} + + + + + ); } +const localStyles = StyleSheet.create({ + content: { + display: "flex", + flex: 2, + }, +}); + export default connect( mapStateToProps, mapDispatchToProps diff --git a/components/time-ticket/screen-time-ticket-clockoff.component.jsx b/components/time-ticket/screen-time-ticket-clockoff.component.jsx index 1487ddd..0120323 100644 --- a/components/time-ticket/screen-time-ticket-clockoff.component.jsx +++ b/components/time-ticket/screen-time-ticket-clockoff.component.jsx @@ -4,7 +4,7 @@ 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 { Button, TextInput, Card } from "react-native-paper"; import { CostCenterSelect } from "../Selects/select-cost-center"; import { selectCurrentEmployee, @@ -120,6 +120,7 @@ export function TimeTicketClockOff({ return ( + )} + From a5cbf88880882d8f6b3ecb2e3f4aab2c40f00b52 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Wed, 17 May 2023 11:53:07 -0400 Subject: [PATCH 063/105] added flex to list in browser --- .../screen-time-ticket-browser.component.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 f90306d..229978d 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 @@ -148,8 +148,8 @@ export function ScreenTimeTicketBrowser({ return ( - - + + Date: Wed, 17 May 2023 13:57:10 -0400 Subject: [PATCH 064/105] added missing return when missing values --- components/time-ticket/screen-time-ticket-clockoff.component.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/components/time-ticket/screen-time-ticket-clockoff.component.jsx b/components/time-ticket/screen-time-ticket-clockoff.component.jsx index 0120323..e9623ca 100644 --- a/components/time-ticket/screen-time-ticket-clockoff.component.jsx +++ b/components/time-ticket/screen-time-ticket-clockoff.component.jsx @@ -65,6 +65,7 @@ export function TimeTicketClockOff({ } else { console.log("missing values!"); setError({ message: "Please make sure all fields have a value." }); + return; } const tempcallobj = { variables: { From e3aee0119a6ad69337ac4f7503f1a0bf4cd4a906 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 18 May 2023 16:52:38 -0400 Subject: [PATCH 065/105] added to clack list for redux fix wrap on TTbrowser --- .../screen-time-ticket-browser.component.jsx | 7 +++---- redux/root.reducer.js | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) 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 229978d..8403287 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 @@ -23,7 +23,7 @@ import { selectCurrentTimeTicketJobId, } from "../../redux/timetickets/timetickets.selectors"; import moment from "moment"; -import { EmployeeClockedInList } from "../time-ticket-lists/employee-clockedin-list.component"; +import EmployeeClockedInList from "../time-ticket-lists/employee-clockedin-list.component"; import { useNavigation } from "@react-navigation/native"; import { INSERT_NEW_TIME_TICKET } from "../../graphql/timetickets.queries"; @@ -61,9 +61,8 @@ export function ScreenTimeTicketBrowser({ const [currentSJobId, setCurrentSJobId] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); - const [insertTimeTicket] = useMutation(INSERT_NEW_TIME_TICKET, { - refetchQueries: ["QUERY_ACTIVE_TIME_TICKETS"], - }); + const [insertTimeTicket] = useMutation(INSERT_NEW_TIME_TICKET); + const [jobCount, setJobCount] = useState(0); // const { error, data } = useQuery(QUERY_EMPLOYEE_BY_ID, { // variables: { id: currentEmployee.technician.id }, // }); diff --git a/redux/root.reducer.js b/redux/root.reducer.js index 1ace819..cb537cf 100644 --- a/redux/root.reducer.js +++ b/redux/root.reducer.js @@ -11,7 +11,7 @@ const persistConfig = { key: "root", storage: AsyncStorage, // whitelist: ["photos"], - blacklist: ["user"], + blacklist: ["user","employee","timeTickets"], }; const rootReducer = combineReducers({ From 54a8f1fa532fbaad3f97a40aff41c31725ca3d6a Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 18 May 2023 17:10:02 -0400 Subject: [PATCH 066/105] fixed employee not logged out when user logs out --- components/sign-out-button/sign-out-button.component.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sign-out-button/sign-out-button.component.jsx b/components/sign-out-button/sign-out-button.component.jsx index 0baa8b8..0e112da 100644 --- a/components/sign-out-button/sign-out-button.component.jsx +++ b/components/sign-out-button/sign-out-button.component.jsx @@ -4,20 +4,22 @@ import { Button } from "react-native"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { signOutStart } from "../../redux/user/user.actions"; +import { employeeSignOut } from "../../redux/employee/employee.actions"; const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser }); const mapDispatchToProps = (dispatch) => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) signOutStart: () => dispatch(signOutStart()), + signOut: () => dispatch(employeeSignOut()), }); -export function SignOutButton({ signOutStart }) { +export function SignOutButton({ signOutStart, signOut }) { const { t } = useTranslation(); return ( - {error ? : null} + {error ? : null} )} From 40e1439ff3900882e05ce160342b7338e4a13a22 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 22 May 2023 07:47:50 -0400 Subject: [PATCH 070/105] added missing setlodaing to false --- .../time-ticket/screen-time-ticket-clockoff.component.jsx | 3 ++- components/time-ticket/screen-time-ticket-create.component.jsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/time-ticket/screen-time-ticket-clockoff.component.jsx b/components/time-ticket/screen-time-ticket-clockoff.component.jsx index 74c57ff..66f37f6 100644 --- a/components/time-ticket/screen-time-ticket-clockoff.component.jsx +++ b/components/time-ticket/screen-time-ticket-clockoff.component.jsx @@ -63,6 +63,7 @@ export function TimeTicketClockOff({ ) { if (isNaN(values.actualhours)|isNaN(values.productivehours)) { console.log("actual hours is NAN!"); + setLoading(false); setError({ message: "Please make sure all fields have valid values." }); return; @@ -160,6 +161,7 @@ export function TimeTicketClockOff({ currentValue={currentSCC} onValueSelected={setCurrentSCC} /> + {error ? : null} - {error ? : null} )} diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index 1ee1953..411f429 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -91,6 +91,7 @@ export function TimeTicketCreate({ ) { if (isNaN(values.actualhours) | isNaN(values.productivehours)) { console.log("actual hours is NAN!"); + setLoading(false); setError({ message: "Please make sure all fields have valid values." }); return; } @@ -249,6 +250,7 @@ export function TimeTicketCreate({ value={values.actualhours} label={"Actual Hours"} /> + {error ? : null} - {error ? : null} )} From 4ebe9a0e4762e0f69c43c4191d58359233b6d4e1 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 22 May 2023 08:09:18 -0400 Subject: [PATCH 071/105] fixed bottom not being able to refresh on dragdown --- .../time-ticket-lists/employee-clockedin-list.component.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/time-ticket-lists/employee-clockedin-list.component.jsx b/components/time-ticket-lists/employee-clockedin-list.component.jsx index 20b483c..2874529 100644 --- a/components/time-ticket-lists/employee-clockedin-list.component.jsx +++ b/components/time-ticket-lists/employee-clockedin-list.component.jsx @@ -72,7 +72,7 @@ export function EmployeeClockedInList({ currentEmployee, isRefresh }) { return ( {jobData ? ( - + You are already clocked in to the following job(s): From bfe749fc54b7c768414fb5e4129b8a927faf3726 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 22 May 2023 08:11:29 -0400 Subject: [PATCH 072/105] edited styling of error message --- components/error-display/error-display.component.jsx | 4 ++-- .../screen-time-ticket-browser.component.jsx | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/components/error-display/error-display.component.jsx b/components/error-display/error-display.component.jsx index c6466c9..725aac9 100644 --- a/components/error-display/error-display.component.jsx +++ b/components/error-display/error-display.component.jsx @@ -14,7 +14,7 @@ const localStyles = StyleSheet.create({ alert: { color: "red", textAlign: "center", - margin: 15, - padding: 15, + margin: 8, + padding: 8, }, }); 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 9946acb..7b5d3e3 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 @@ -172,12 +172,13 @@ export function ScreenTimeTicketBrowser({ currentRatesNCostCenters={currentRatesNCostCenters} onValueSelected={setCurrentSCC} /> - {error && error?.message ? ( ) : null} + + {/* Date: Mon, 22 May 2023 08:44:01 -0400 Subject: [PATCH 073/105] fixed jobselect dropdown not clearing on clockin --- components/Selects/select-job-id.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/Selects/select-job-id.jsx b/components/Selects/select-job-id.jsx index 404888e..2e438c7 100644 --- a/components/Selects/select-job-id.jsx +++ b/components/Selects/select-job-id.jsx @@ -136,7 +136,7 @@ export function JobIdSearchSelect( onFocus={() => setIsFocus(true)} onBlur={() => setIsFocus(false)} data={selectorData} - value={selectedvalue} //{selectedvalue} + value={props.currentValue?.value} //{selectedvalue} onChange={(item) => props.onJobSelected(item)}//TODO: add setIsFocus(false); to this // { // console.log("onValueSelected!!!!"); From 69df9af7e1e879e9de5d9c20955e7e9542dd0da5 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 1 Jun 2023 09:52:36 -0400 Subject: [PATCH 074/105] removed search bar from cost center dropdown --- components/Selects/select-cost-center.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/Selects/select-cost-center.jsx b/components/Selects/select-cost-center.jsx index 136c076..f048aca 100644 --- a/components/Selects/select-cost-center.jsx +++ b/components/Selects/select-cost-center.jsx @@ -53,7 +53,7 @@ export function CostCenterSelect(props) { selectedTextStyle={styles.selectedTextStyle} inputSearchStyle={styles.inputSearchStyle} iconStyle={styles.iconStyle} - search + maxHeight={300} labelField="label" valueField="value" From a6f8d109aa6d5b4ad027cf74d836decafcfa64f4 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 1 Jun 2023 09:59:37 -0400 Subject: [PATCH 075/105] Update EmployeeId field on the log in screen --- translations/en-US/common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translations/en-US/common.json b/translations/en-US/common.json index c3af9b5..6243d06 100644 --- a/translations/en-US/common.json +++ b/translations/en-US/common.json @@ -316,7 +316,7 @@ "wrongpin": "The pin you entered is not correct." }, "fields": { - "employeeid": "EmployeeID", + "employeeid": "Employee ID", "pin": "PIN" }, "titles": { From c952b3cf814d4881649562a447831136738166f1 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 1 Jun 2023 10:02:59 -0400 Subject: [PATCH 076/105] Update Time Tickets location --- components/screen-main/screen-main.component.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/screen-main/screen-main.component.jsx b/components/screen-main/screen-main.component.jsx index f1cf32e..667bb4b 100644 --- a/components/screen-main/screen-main.component.jsx +++ b/components/screen-main/screen-main.component.jsx @@ -243,11 +243,6 @@ const BottomTabsNavigator = () => ( }} component={MediaBrowserStackNavigator} /> - ( }} component={TimeTicketBrowserStackNavigator} /> + ); From 00316dd6d059c5dc43163abc9784aa19682e9b4c Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 1 Jun 2023 10:38:21 -0400 Subject: [PATCH 077/105] Update Date Displayed on entering ticket manually --- components/time-ticket/screen-time-ticket-create.component.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index 411f429..82a965b 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -207,7 +207,7 @@ export function TimeTicketCreate({ style={localStyles.dateButton} > - Ticket Date: {date2.toLocaleDateString()} + Ticket Date: {date2.toLocaleDateString('en-US', { day: '2-digit', month: '2-digit', year: 'numeric' })} Date: Fri, 2 Jun 2023 13:34:42 -0400 Subject: [PATCH 078/105] update Employee field to show first and last name --- .../screen-time-ticket-create.component.jsx | 5 +- redux/employee/employee.selectors.js | 49 ++++++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index 82a965b..449cbe5 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -11,6 +11,7 @@ import DateTimePickerModal from "react-native-modal-datetime-picker"; import { selectCurrentEmployee, selectRates, + selectEmployeeFullName } from "../../redux/employee/employee.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; import { useCallback } from "react"; @@ -29,6 +30,7 @@ const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, currentRatesNCostCenters: selectRates, currentBodyshop: selectBodyshop, + currentEmployeeFullName: selectEmployeeFullName }); // const mapDispatchToProps = (dispatch) => ({}); @@ -36,6 +38,7 @@ export function TimeTicketCreate({ currentEmployee, currentRatesNCostCenters, currentBodyshop, + currentEmployeeFullName }) { const navigation = useNavigation(); const { t } = useTranslation(); @@ -183,7 +186,7 @@ export function TimeTicketCreate({ initialValues={{ jobid: { currentSJobId }, ticketdate: date2.toLocaleDateString(), - employee: currentEmployee.technician.first_name, + employee: {currentEmployeeFullName}, costcenter: { currentSCC }, productivehours: "", actualhours: "", diff --git a/redux/employee/employee.selectors.js b/redux/employee/employee.selectors.js index 00def96..1818289 100644 --- a/redux/employee/employee.selectors.js +++ b/redux/employee/employee.selectors.js @@ -24,5 +24,52 @@ export const selectGettingRates = createSelector( ); export const selectTechnician = createSelector( [selectEmployee], - (employee) => employee.currentEmployee?.technician + (employee) => { + if (!employee.currentEmployee || !employee.currentEmployee.technician) { + // console.info("selectTechnician returning null"); + return null; + } + // console.info("selectTechnician returning :", employee.currentEmployee.technician); + return employee.currentEmployee.technician; + } +); +export const selectEmployeeFirstName = createSelector( + [selectTechnician], + (techResults) => { + if (!techResults || !techResults.first_name) { + // console.info("selectEmployeeFirstName returning null"); + return null; + } + // console.info("selectEmployeeFirstName returning :", techResults.first_name); + return techResults.first_name; + } +); +export const selectEmployeeLastName = createSelector( + [selectTechnician], + (techResults) => { + if (!techResults || !techResults.last_name) { + // console.info("selectEmployeeLastName returning null"); + return null; + } + // console.info("selectEmployeeLastName returning :", techResults.last_name); + return techResults.last_name; + } +); +export const selectEmployeeFullName = createSelector( + [selectEmployeeFirstName,selectEmployeeLastName], + (fName,lName) => { + if (!fName && !lName) { + // console.warn("selectEmployeeFullName returning null"); + return null; + } + if (fName) { + if(lName){ + return fName + " " + lName; + } else { + return fName; + } + } else { + return lName; + } + } ); From cf24d49f9fc70b069bc80984071cc3e306adee7d Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Fri, 2 Jun 2023 13:50:39 -0400 Subject: [PATCH 079/105] numeric keypad for Productive and Actual Hours --- .../time-ticket/screen-time-ticket-clockoff.component.jsx | 2 ++ .../time-ticket/screen-time-ticket-create.component.jsx | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/time-ticket/screen-time-ticket-clockoff.component.jsx b/components/time-ticket/screen-time-ticket-clockoff.component.jsx index 66f37f6..3a78a31 100644 --- a/components/time-ticket/screen-time-ticket-clockoff.component.jsx +++ b/components/time-ticket/screen-time-ticket-clockoff.component.jsx @@ -147,6 +147,7 @@ export function TimeTicketClockOff({ onBlur={handleBlur("actualhours")} value={values.actualhours} label={"Actual Hours"} + keyboardType="numeric" /> @@ -244,6 +242,7 @@ export function TimeTicketCreate({ onBlur={handleBlur("productivehours")} value={values.productivehours} label={"Productive Hours"} + keyboardType="numeric" /> {error ? : null} - - {/* - - */} -
+ - - - {/* } > - - - + - */} -
+ ); } diff --git a/components/time-ticket-lists/employee-clockedin-list.component.jsx b/components/time-ticket-lists/employee-clockedin-list.component.jsx index 2874529..cc939c6 100644 --- a/components/time-ticket-lists/employee-clockedin-list.component.jsx +++ b/components/time-ticket-lists/employee-clockedin-list.component.jsx @@ -24,10 +24,7 @@ const mapStateToProps = createStructuredSelector({ export function EmployeeClockedInList({ currentEmployee, isRefresh }) { const [refreshKey, setRefreshKey] = useState(isRefresh); const [jobData, setJobData] = useState(data); - console.info( - "EmployeeClockedInList, QUERY_ACTIVE_TIME_TICKETS called.", - currentEmployee - ); + // console.info("EmployeeClockedInList, QUERY_ACTIVE_TIME_TICKETS called.",currentEmployee); // console.info( // "EmployeeClockedInList, isRefresh :", @@ -42,6 +39,9 @@ export function EmployeeClockedInList({ currentEmployee, isRefresh }) { // console.log("teste: ", result); // } // fetchData(); + if(isRefresh){ + refetch(); + } console.log("useEffect: ", isRefresh); // setRefreshKey(isRefresh); From 1e5dac93329776d72f02175f535379a92412fdc5 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Fri, 2 Jun 2023 16:06:33 -0400 Subject: [PATCH 081/105] removed comment --- components/time-ticket-items/clockedin-list-item.component.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/time-ticket-items/clockedin-list-item.component.jsx b/components/time-ticket-items/clockedin-list-item.component.jsx index 0987be0..1f9fbf4 100644 --- a/components/time-ticket-items/clockedin-list-item.component.jsx +++ b/components/time-ticket-items/clockedin-list-item.component.jsx @@ -12,7 +12,7 @@ const mapDispatchToProps = (dispatch) => ({ }); export function ClockedinListItem({ setTmTicketJobIdRedux, ticket }) { - console.log("makeNavToTimeTicketClockOff, handleRefresh:"); + // console.log("makeNavToTimeTicketClockOff, handleRefresh:"); const { t } = useTranslation(); const navigation = useNavigation(); From c27eb29b6327729d40801b2f9205078843775c85 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Fri, 2 Jun 2023 16:21:58 -0400 Subject: [PATCH 082/105] Update Text Displayed on Job Id Search Dropdown --- components/Selects/select-job-id.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/Selects/select-job-id.jsx b/components/Selects/select-job-id.jsx index 2e438c7..b95cd62 100644 --- a/components/Selects/select-job-id.jsx +++ b/components/Selects/select-job-id.jsx @@ -131,7 +131,7 @@ export function JobIdSearchSelect( maxHeight={300} labelField="label" valueField="value" - placeholder={!isFocus ? "Job Id to Post Against" : "..."} + placeholder={!isFocus ? "RO #" : "..."} searchPlaceholder="Search..." onFocus={() => setIsFocus(true)} onBlur={() => setIsFocus(false)} From 5e107bc76707b40633ddbe3219f7eaaa316a28e2 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 5 Jun 2023 11:50:58 -0400 Subject: [PATCH 083/105] display labor type when logging in as dealership --- components/Selects/select-cost-center.jsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/components/Selects/select-cost-center.jsx b/components/Selects/select-cost-center.jsx index f048aca..a2703e0 100644 --- a/components/Selects/select-cost-center.jsx +++ b/components/Selects/select-cost-center.jsx @@ -8,6 +8,7 @@ import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors"; import { QUERY_EMPLOYEE_BY_ID } from "../../graphql/employees.queries"; import { useEffect } from "react"; +import { t } from "i18next"; const data = [ { label: "Item 1", value: "1" }, @@ -15,16 +16,17 @@ const data = [ { label: "Item 3", value: "3" }, ]; -// const mapStateToProps = createStructuredSelector({ -// bodyshop: selectBodyshop, -// timeTicketJobId: selectCurrentTimeTicketJobId, -// timeTicketJob: selectCurrentTimeTicketJob, -// }); +const mapStateToProps = createStructuredSelector({ + bodyshop: selectBodyshop + // timeTicketJobId: selectCurrentTimeTicketJobId, + // timeTicketJob: selectCurrentTimeTicketJob, + }); // const mapDispatchToProps = {}; export function CostCenterSelect(props) { const currentRatesNCostCenters = props.currentRatesNCostCenters; + const bodyshop = props.bodyshop; const [value, setValue] = useState(null); const [isFocus, setIsFocus] = useState(false); @@ -37,7 +39,10 @@ export function CostCenterSelect(props) { for (let i = 0; i < count; i++) { selectDataArray.push({ value: currentRatesNCostCenters[i].cost_center, - label: currentRatesNCostCenters[i].cost_center, + label: bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber ? t( + `joblines.fields.lbr_types.${currentRatesNCostCenters[i].cost_center.toUpperCase()}` + ) + : currentRatesNCostCenters[i].cost_center, rate: currentRatesNCostCenters[i].rate, }); } @@ -73,7 +78,7 @@ export function CostCenterSelect(props) { ); } -export default connect(null, null)(CostCenterSelect); +export default connect(mapStateToProps, null)(CostCenterSelect); const styles = StyleSheet.create({ container: { From aca336fceb0a22f5e4050e808a2452bcfd2f52c9 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 5 Jun 2023 13:14:45 -0400 Subject: [PATCH 084/105] fixed filtering Invoiced ROs for JobIdSearchSelect --- .../screen-time-ticket-browser.component.jsx | 22 +++++++++++++++++-- .../screen-time-ticket-clockoff.component.jsx | 2 +- .../screen-time-ticket-create.component.jsx | 5 +++-- 3 files changed, 24 insertions(+), 5 deletions(-) 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 fc0f659..9609671 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 @@ -14,7 +14,7 @@ import { selectCurrentEmployee, selectRates, selectGettingRates, selectSignInE import { selectBodyshop } from "../../redux/user/user.selectors"; import { JobIdSearchSelect } from "../Selects/select-job-id"; -import { CostCenterSelect } from "../Selects/select-cost-center"; +import CostCenterSelect from "../Selects/select-cost-center"; import ErrorDisplay from "../error-display/error-display.component"; import { selectCurrentTimeTicketJob, selectCurrentTimeTicketJobId, } from "../../redux/timetickets/timetickets.selectors"; @@ -25,6 +25,8 @@ import { QUERY_ACTIVE_TIME_TICKETS } from "../../graphql/timetickets.queries"; import EmployeeClockedInList from "../time-ticket-lists/employee-clockedin-list.component"; import { logImEXEvent } from "../../firebase/firebase.analytics"; import StyleRepeater from "../style-repeater/style-repeater"; +// import SignOutButton from "../Buttons/employee-sign-out-button.component"; +// import AddTimeTicketButton from "../Buttons/create-time-ticket-button.component"; const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, @@ -135,7 +137,9 @@ export function ScreenTimeTicketBrowser({ > - + } + /> {currentEmployeeFullName && ( {currentEmployeeFullName} @@ -143,11 +147,24 @@ export function ScreenTimeTicketBrowser({ + + // + // + // } + /> + Clock In + diff --git a/components/time-ticket/screen-time-ticket-clockoff.component.jsx b/components/time-ticket/screen-time-ticket-clockoff.component.jsx index 3a78a31..6978fc4 100644 --- a/components/time-ticket/screen-time-ticket-clockoff.component.jsx +++ b/components/time-ticket/screen-time-ticket-clockoff.component.jsx @@ -5,7 +5,7 @@ import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { Button, TextInput, Card } from "react-native-paper"; -import { CostCenterSelect } from "../Selects/select-cost-center"; +import CostCenterSelect from "../Selects/select-cost-center"; import { selectCurrentEmployee, selectRates, diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index c2b2e71..2e4488c 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -5,7 +5,7 @@ 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 CostCenterSelect from "../Selects/select-cost-center"; import { JobIdSearchSelect } from "../Selects/select-job-id"; import DateTimePickerModal from "react-native-modal-datetime-picker"; import { @@ -198,8 +198,9 @@ export function TimeTicketCreate({ {/* Below will be replaced with a Date Picker*/} {/* */} From 43151aaa2deb5cb2c27855d4c2427f57527eff49 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 5 Jun 2023 16:43:58 -0400 Subject: [PATCH 085/105] removed unused components --- components/Selects/select-job-name.jsx | 168 ------------------ ...-allocations-table-container.component.jsx | 39 ---- 2 files changed, 207 deletions(-) delete mode 100644 components/Selects/select-job-name.jsx delete mode 100644 components/labor-allocations-table/labor-allocations-table-container.component.jsx diff --git a/components/Selects/select-job-name.jsx b/components/Selects/select-job-name.jsx deleted file mode 100644 index 8ef7f6a..0000000 --- a/components/Selects/select-job-name.jsx +++ /dev/null @@ -1,168 +0,0 @@ -import { useLazyQuery } from "@apollo/client"; -import React, { forwardRef, useState, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import _ from "lodash"; - -import { - SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE, - SEARCH_JOBS_FOR_AUTOCOMPLETE, -} from "../../graphql/jobs.queries"; -import { StyleSheet, Text, View } from "react-native"; -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 not currently used - -export function JobSearchSelect( - convertedOnly = false, - notInvoiced = false, - notExported = true, - clm_no = false, - ...restProps -) { - const { t } = useTranslation(); - const [selectorData, setSelectorData] = useState([]); - const [selectedvalue, setSelectedValue] = useState(null); - const [isFocus, setIsFocus] = useState(false); - - const [theOptions, setTheOptions] = useState([]); - - const [callSearch, { loading, error, data }] = useLazyQuery( - SEARCH_JOBS_FOR_AUTOCOMPLETE, - {} - ); - const [callIdSearch, { loading: idLoading, error: idError, data: idData }] = - useLazyQuery(SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE); - - const executeSearch = (v) => { - if (v && v !== "") callSearch(v); - }; - const debouncedExecuteSearch = _.debounce(executeSearch, 500); - - const handleSearch = (value) => { - debouncedExecuteSearch({ - variables: { - search: value, - ...(convertedOnly || notExported - ? { - ...(convertedOnly ? { isConverted: true } : {}), - ...(notExported ? { notExported: true } : {}), - ...(notInvoiced ? { notInvoiced: true } : {}), - } - : {}), - }, - }); - }; - - useEffect(() => { - if (restProps.value) { - callIdSearch({ variables: { id: restProps.value } }); - } - }, [restProps.value, callIdSearch]); - - useEffect(() => { - setTheOptions( - _.uniqBy( - [ - ...(idData && idData.jobs_by_pk ? [idData.jobs_by_pk] : []), - ...(data && data.search_jobs ? data.search_jobs : []), - ], - "id" - ) - ); - }, [data, idData]); - - useEffect(() => { - var count = Object.keys(theOptions).length; - 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 || "" - // }`, - - }); - } - setSelectorData(selectDataArray); - }, [theOptions]); - return ( - - setIsFocus(true)} - onBlur={() => setIsFocus(false)} - onChange={(item) => { - console.log(item); - setSelectedValue(item.value); - setIsFocus(false); - }} - onChangeText={(search) => { - handleSearch(search); - }} - /> - {/* {theOptions ? console.log(theOptions): null} */} - - ); -} - -export default connect(null, null)(JobSearchSelect); - -const styles = StyleSheet.create({ - container: { - padding: 16, - justifyContent: "center", - alignContent: "center", - }, - dropdown: { - height: 50, - borderColor: "gray", - borderWidth: 0.5, - borderRadius: 8, - paddingHorizontal: 8, - }, - icon: { - marginRight: 5, - }, - label: { - position: "absolute", - backgroundColor: "white", - left: 22, - top: 8, - zIndex: 999, - paddingHorizontal: 8, - fontSize: 14, - }, - placeholderStyle: { - fontSize: 16, - }, - selectedTextStyle: { - fontSize: 16, - }, - iconStyle: { - width: 20, - height: 20, - }, - inputSearchStyle: { - height: 40, - fontSize: 16, - }, -}); diff --git a/components/labor-allocations-table/labor-allocations-table-container.component.jsx b/components/labor-allocations-table/labor-allocations-table-container.component.jsx deleted file mode 100644 index ff85fe4..0000000 --- a/components/labor-allocations-table/labor-allocations-table-container.component.jsx +++ /dev/null @@ -1,39 +0,0 @@ -import React from "react"; -import { useTranslation } from "react-i18next"; -import { StyleSheet, View } from "react-native"; -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); From 088945399813bd0cf716d05911d3e2032cbb1633 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Mon, 5 Jun 2023 16:50:12 -0400 Subject: [PATCH 086/105] Update time ticket areas added to use translations --- components/Selects/select-cost-center.jsx | 10 +-- components/Selects/select-job-id.jsx | 6 +- .../screen-main/screen-main.component.jsx | 3 +- .../screen-time-ticket-browser.component.jsx | 12 ++-- .../clockedin-list-item.component.jsx | 8 +-- .../employee-clockedin-list.component.jsx | 9 +-- .../screen-time-ticket-clockoff.component.jsx | 25 ++++--- .../screen-time-ticket-create.component.jsx | 33 +++------ translations/en-US/common.json | 71 +++++++++++++++++-- translations/es-MX/common.json | 71 +++++++++++++++++-- translations/fr-CA/common.json | 71 +++++++++++++++++-- 11 files changed, 235 insertions(+), 84 deletions(-) diff --git a/components/Selects/select-cost-center.jsx b/components/Selects/select-cost-center.jsx index a2703e0..581f9a0 100644 --- a/components/Selects/select-cost-center.jsx +++ b/components/Selects/select-cost-center.jsx @@ -10,12 +10,6 @@ import { QUERY_EMPLOYEE_BY_ID } from "../../graphql/employees.queries"; import { useEffect } from "react"; import { t } from "i18next"; -const data = [ - { label: "Item 1", value: "1" }, - { label: "Item 2", value: "3" }, - { label: "Item 3", value: "3" }, -]; - const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop // timeTicketJobId: selectCurrentTimeTicketJobId, @@ -62,8 +56,8 @@ export function CostCenterSelect(props) { maxHeight={300} labelField="label" valueField="value" - placeholder={!isFocus ? "Select Cost Center" : "..."} - searchPlaceholder="Search..." + placeholder={!isFocus ? t("selectcostcenter.labels.placeholder") : t("selectcostcenter.labels.selectedplaceholder")} + searchPlaceholder={t("selectcostcenter.labels.searchplaceholder")} onFocus={() => setIsFocus(true)} onBlur={() => setIsFocus(false)} data={costCenters} diff --git a/components/Selects/select-job-id.jsx b/components/Selects/select-job-id.jsx index b95cd62..ef1caf2 100644 --- a/components/Selects/select-job-id.jsx +++ b/components/Selects/select-job-id.jsx @@ -96,7 +96,7 @@ export function JobIdSearchSelect( useEffect(() => { // console.log("useEfectDependentOn: [theOptions]"); var count = Object.keys(theOptions).length; - console.log("useEfectDependentOn: [theOptions] count:", count); + // console.log("useEfectDependentOn: [theOptions] count:", count); let selectDataArray = []; for (let i = 0; i < count; i++) { selectDataArray.push({ @@ -131,8 +131,8 @@ export function JobIdSearchSelect( maxHeight={300} labelField="label" valueField="value" - placeholder={!isFocus ? "RO #" : "..."} - searchPlaceholder="Search..." + placeholder={!isFocus ? t("selectjobid.labels.placeholder") : t("selectjobid.labels.selectedplaceholder")} + searchPlaceholder={t("selectjobid.labels.searchplaceholder")} onFocus={() => setIsFocus(true)} onBlur={() => setIsFocus(false)} data={selectorData} diff --git a/components/screen-main/screen-main.component.jsx b/components/screen-main/screen-main.component.jsx index 667bb4b..541ec2a 100644 --- a/components/screen-main/screen-main.component.jsx +++ b/components/screen-main/screen-main.component.jsx @@ -186,7 +186,7 @@ const TimeTicketBrowserStackNavigator = connect( ({ - title: "Clock Off", + title: i18n.t("timeticketclockoff.titles.clockoff"), })} component={ScreenTimeTicketClockoffComponent} /> @@ -217,7 +217,6 @@ const BottomTabsNavigator = () => ( } else if (route.name === "MediaBrowserTab") { iconName = "ios-camera"; } else if (route.name === "TimeTicketBrowserTab") { - //ADDED JF check for route.name for TimeTicketBrowserTab. Also icon ios-stopwatch-outline iconName = "ios-stopwatch-outline"; } else { //iconName = "customerservice"; 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 9609671..6eb7c5e 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 @@ -25,6 +25,7 @@ import { QUERY_ACTIVE_TIME_TICKETS } from "../../graphql/timetickets.queries"; import EmployeeClockedInList from "../time-ticket-lists/employee-clockedin-list.component"; import { logImEXEvent } from "../../firebase/firebase.analytics"; import StyleRepeater from "../style-repeater/style-repeater"; +import { useTranslation } from "react-i18next"; // import SignOutButton from "../Buttons/employee-sign-out-button.component"; // import AddTimeTicketButton from "../Buttons/create-time-ticket-button.component"; @@ -55,6 +56,7 @@ export function ScreenTimeTicketBrowser({ currentSelectedTimeTicketJobId, currentEmployeeFullName, }) { + const { t } = useTranslation(); const [currentSCC, setCurrentSCC] = useState(null); const [currentSJobId, setCurrentSJobId] = useState(null); const [loading, setLoading] = useState(false); @@ -65,7 +67,7 @@ export function ScreenTimeTicketBrowser({ }); const handleFinish = async (values) => { - console.log("handleFinish called in ScreenTimeTicketBrowser"); + // console.log("handleFinish called in ScreenTimeTicketBrowser"); setLoading(true); setError(null); @@ -77,7 +79,7 @@ export function ScreenTimeTicketBrowser({ } else { // console.log("missing values!"); setLoading(false); - setError({ message: "Please make sure all fields have a value." }); + setError({ message: t("timeticketbrowser.errors.missingvalues") }); return; } @@ -137,7 +139,7 @@ export function ScreenTimeTicketBrowser({ > - } /> @@ -147,7 +149,7 @@ export function ScreenTimeTicketBrowser({ - // // diff --git a/components/time-ticket-items/clockedin-list-item.component.jsx b/components/time-ticket-items/clockedin-list-item.component.jsx index 1f9fbf4..7505208 100644 --- a/components/time-ticket-items/clockedin-list-item.component.jsx +++ b/components/time-ticket-items/clockedin-list-item.component.jsx @@ -36,16 +36,16 @@ export function ClockedinListItem({ setTmTicketJobIdRedux, ticket }) { /> - Vehicle : + {t("clockedinlistitem.labels.vehicle")} {`${ticket.job.v_model_yr || ""} ${ticket.job.v_make_desc || ""} ${ ticket.job.v_model_desc || "" }`} - Clocked In : {ticket.clockon} + {t("clockedinlistitem.labels.clockedin")}{ticket.clockon} - Cost Center :{" "} + {t("clockedinlistitem.labels.costcenter")} {ticket.cost_center === "timetickets.labels.shift" ? t(ticket.cost_center) : ticket.cost_center} @@ -53,7 +53,7 @@ export function ClockedinListItem({ setTmTicketJobIdRedux, ticket }) { diff --git a/components/time-ticket-lists/employee-clockedin-list.component.jsx b/components/time-ticket-lists/employee-clockedin-list.component.jsx index cc939c6..34de696 100644 --- a/components/time-ticket-lists/employee-clockedin-list.component.jsx +++ b/components/time-ticket-lists/employee-clockedin-list.component.jsx @@ -42,7 +42,7 @@ export function EmployeeClockedInList({ currentEmployee, isRefresh }) { if(isRefresh){ refetch(); } - console.log("useEffect: ", isRefresh); + // console.log("useEffect: ", isRefresh); // setRefreshKey(isRefresh); }, [isRefresh]); @@ -62,19 +62,16 @@ export function EmployeeClockedInList({ currentEmployee, isRefresh }) { if (error) return ; const onRefresh = async () => { - console.info("EmployeeClockedInList, onRefresh."); + // console.info("EmployeeClockedInList, onRefresh."); return refetch(); }; - - - return ( {jobData ? ( - You are already clocked in to the following job(s): + {t("employeeclockedinlist.labels.alreadyclockedon")} - Clock Off + {t("timeticketclockoff.actions.clockoff")} )} diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index 2e4488c..cc81872 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -52,13 +52,6 @@ export function TimeTicketCreate({ // const [currentSJob, setCurrentSJob] = useState(null); const [currentSJobId, setCurrentSJobId] = useState(null); - // const wrapperSetCurrentSJobState = useCallback( - // (val) => { - // setCurrentSJob(val); - // }, - // [setCurrentSJob] - // ); - const showDatePicker = () => { setDatePickerVisibility(true); }; @@ -67,7 +60,6 @@ export function TimeTicketCreate({ }; const handleConfirm = (date) => { setDate2(date); - //console.war1n("A date has been picked: ", date); hideDatePicker(); }; @@ -75,7 +67,7 @@ export function TimeTicketCreate({ const handleFinish = async (values) => { logImEXEvent("handleFinish_called_in_TimeTicketCreate"); - console.log("handleFinish called in TimeTicketCreate"); + // console.log("handleFinish called in TimeTicketCreate"); setError(null); setLoading(true); @@ -93,17 +85,17 @@ export function TimeTicketCreate({ !!values.actualhours ) { if (isNaN(values.actualhours) | isNaN(values.productivehours)) { - console.log("actual hours is NAN!"); + // console.log("actual hours is NAN!"); setLoading(false); - setError({ message: "Please make sure all fields have valid values." }); + setError({ message: t("createtimeticket.errors.nan") }); return; } setError(null); - console.log("have all values"); + // console.log("have all values"); } else { - console.log("missing values!"); + // console.log("missing values!"); setLoading(false); - setError({ message: "Please make sure all fields have a value." }); + setError({ message: t("createtimeticket.errors.missingvalues")}); return; } @@ -211,7 +203,7 @@ export function TimeTicketCreate({ style={localStyles.dateButton} > - Ticket Date: {date2.toLocaleDateString('en-US', { day: '2-digit', month: '2-digit', year: 'numeric' })} + {t("createtimeticket.actions.ticketdate")}{date2.toLocaleDateString('en-US', { day: '2-digit', month: '2-digit', year: 'numeric' })} - {/* Below will set to auto fill with current employee */} - - {error ? : null} @@ -261,7 +250,7 @@ export function TimeTicketCreate({ loading={loading} title="Submit" > - Create Ticket + {t("createtimeticket.actions.createticket")} )} diff --git a/translations/en-US/common.json b/translations/en-US/common.json index 6243d06..41fe116 100644 --- a/translations/en-US/common.json +++ b/translations/en-US/common.json @@ -330,13 +330,15 @@ "ticket":"Ticket", "timetickets": "Time Tickets", "detail": "Time Ticket Details", - "notickets": "There are no active tickets." + "notickets": "There are no active tickets.", + "clockin": "Clock In" }, "labels": { - "converting": "Converting", - "selectjob": "--- Select a ticket ---", - "selectticketassetselector": "Please select a ticket to update. ", - "uploading": "Uploading" + "loggedinemployee": "Logged in Employee", + "clockintojob": "Clock Into Job" + }, + "errors": { + "missingvalues": "Please make sure all fields have a value." }, "titles": { "timeticketbrowsertab": "Time Tickets" @@ -349,13 +351,22 @@ "ticket":"Ticket", "timetickets": "Time Tickets", "detail": "Time Ticket Details", - "notickets": "There are no active tickets." + "notickets": "There are no active tickets.", + "ticketdate": "Ticket Date: ", + "createticket": "Create Ticket" }, "labels": { "converting": "Converting", "selectjob": "--- Select a ticket ---", "selectticketassetselector": "Please select a ticket to update. ", - "uploading": "Uploading" + "uploading": "Uploading", + "employeeplaceholder": "Employee", + "actualhoursplaceholder": "Actual Hours", + "productivehoursplaceholder": "Productive Hours" + }, + "errors": { + "nan": "Please make sure all fields have valid values.", + "missingvalues": "Please make sure all fields have a value." }, "titles": { "createtimeticket": "Create a Time Ticket" @@ -450,6 +461,52 @@ "requiredifparttype": "Required if a part type has been specified.", "zeropriceexistingpart": "This line cannot have any price since it uses an existing part." } + }, + "timeticketclockoff":{ + "actions": { + "clockoff": "Clock Off", + "noinfo": "There is no info to display." + }, + "labels": { + "actualhoursplaceholder": "Actual Hours", + "productivehoursplaceholder": "Productive Hours" + }, + "errors": { + "nan": "Please make sure all fields have valid values.", + "missingvalues": "Please make sure all fields have a value." + }, + "titles": { + "clockoff": "Clock Off" + } + }, + "selectjobid":{ + "labels": { + "placeholder": "RO #", + "selectedplaceholder": "...", + "searchplaceholder": "Search..." + } + }, + "selectcostcenter":{ + "labels": { + "placeholder": "Select Cost Center", + "selectedplaceholder": "...", + "searchplaceholder": "Search..." + } + }, + "employeeclockedinlist": { + "labels": { + "alreadyclockedon": "You are already clocked in to the following job(s):" + } + }, + "clockedinlistitem": { + "labels": { + "vehicle": "Vehicle : ", + "clockedin": "Clocked In : ", + "costcenter": "Cost Center : " + }, + "actions": { + "clockout": "Clock Out" + } } } } diff --git a/translations/es-MX/common.json b/translations/es-MX/common.json index 0d4aac5..60f8aa7 100644 --- a/translations/es-MX/common.json +++ b/translations/es-MX/common.json @@ -330,13 +330,15 @@ "ticket": "", "timetickets": "", "detail": "", - "notickets": "" + "notickets": "", + "clockin": "" }, "labels": { - "converting": "", - "selectjob": "", - "selectticketassetselector": "", - "uploading": "" + "loggedinemployee": "", + "clockintojob": "" + }, + "errors": { + "missingvalues": "" }, "titles": { "timeticketbrowsertab": "" @@ -349,13 +351,22 @@ "ticket":" ", "timetickets": "", "detail": "", - "notickets": "" + "notickets": "", + "ticketdate": "", + "createticket": "" }, "labels": { "converting": "", "selectjob": "", "selectticketassetselector": "", - "uploading": "" + "uploading": "", + "employeeplaceholder": "", + "actualhoursplaceholder": "", + "productivehoursplaceholder": "" + }, + "errors": { + "nan": "", + "missingvalues": "" }, "titles": { "createtimeticket": "" @@ -450,6 +461,52 @@ "requiredifparttype": "", "zeropriceexistingpart": "" } + }, + "timeticketclockoff":{ + "actions": { + "clockoff": "", + "noinfo": "" + }, + "labels": { + "actualhoursplaceholder": "", + "productivehoursplaceholder": "" + }, + "errors": { + "nan": "", + "missingvalues": "" + }, + "titles": { + "clockoff": "" + } + }, + "selectjobid":{ + "labels": { + "placeholder": "", + "selectedplaceholder": "...", + "searchplaceholder": "" + } + }, + "selectcostcenter":{ + "labels": { + "placeholder": "", + "selectedplaceholder": "...", + "searchplaceholder": "" + } + }, + "employeeclockedinlist": { + "labels": { + "alreadyclockedon": "" + } + }, + "clockedinlistitem": { + "labels": { + "vehicle": "", + "clockedin": "", + "costcenter": "" + }, + "actions": { + "clockout": "" + } } } } diff --git a/translations/fr-CA/common.json b/translations/fr-CA/common.json index efb30bd..d6abc2d 100644 --- a/translations/fr-CA/common.json +++ b/translations/fr-CA/common.json @@ -330,13 +330,15 @@ "ticket": "", "timetickets": "", "detail": "", - "notickets": "" + "notickets": "", + "clockin": "" }, "labels": { - "converting": "", - "selectjob": "", - "selectticketassetselector": "", - "uploading": "" + "loggedinemployee": "", + "clockintojob": "" + }, + "errors": { + "missingvalues": "" }, "titles": { "timeticketbrowsertab": "" @@ -349,13 +351,22 @@ "ticket":" ", "timetickets": "", "detail": "", - "notickets": "" + "notickets": "", + "ticketdate": "", + "createticket": "" }, "labels": { "converting": "", "selectjob": "", "selectticketassetselector": "", - "uploading": "" + "uploading": "", + "employeeplaceholder": "", + "actualhoursplaceholder": "", + "productivehoursplaceholder": "" + }, + "errors": { + "nan": "", + "missingvalues": "" }, "titles": { "createtimeticket": "" @@ -450,6 +461,52 @@ "requiredifparttype": "", "zeropriceexistingpart": "" } + }, + "timeticketclockoff":{ + "actions": { + "clockoff": "", + "noinfo": "" + }, + "labels": { + "actualhoursplaceholder": "", + "productivehoursplaceholder": "" + }, + "errors": { + "nan": "", + "missingvalues": "" + }, + "titles": { + "clockoff": "" + } + }, + "selectjobid":{ + "labels": { + "placeholder": "", + "selectedplaceholder": "...", + "searchplaceholder": "" + } + }, + "selectcostcenter":{ + "labels": { + "placeholder": "", + "selectedplaceholder": "...", + "searchplaceholder": "" + } + }, + "employeeclockedinlist": { + "labels": { + "alreadyclockedon": "" + } + }, + "clockedinlistitem": { + "labels": { + "vehicle": "", + "clockedin": "", + "costcenter": "" + }, + "actions": { + "clockout": "" + } } } } From ae8a0fb94364837b892e4ee12df89d07a769376b Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Tue, 6 Jun 2023 17:23:02 -0400 Subject: [PATCH 087/105] Added validating claiming hours using shop setting --- .../labor-allocations-table.component.jsx | 49 ++++++++++++------- .../screen-time-ticket-clockoff.component.jsx | 46 ++++++++++++----- graphql/bodyshop.queries.js | 3 +- redux/user/user.selectors.js | 12 +++++ translations/en-US/common.json | 3 +- translations/es-MX/common.json | 3 +- translations/fr-CA/common.json | 3 +- 7 files changed, 85 insertions(+), 34 deletions(-) diff --git a/components/labor-allocations-table/labor-allocations-table.component.jsx b/components/labor-allocations-table/labor-allocations-table.component.jsx index bfb3011..8a44a75 100644 --- a/components/labor-allocations-table/labor-allocations-table.component.jsx +++ b/components/labor-allocations-table/labor-allocations-table.component.jsx @@ -17,12 +17,13 @@ const mapStateToProps = createStructuredSelector({ technician: selectCurrentEmployee, }); -export function LaborAllocationsTable({ jobId, bodyshop, technician }) { - // console.log("LaborAllocationsTable, jobId", jobId); +export function LaborAllocationsTable({ jobId, bodyshop, technician,costCenterDiff,selectedCostCenter}) { + // console.log("LaborAllocationsTable, costCenterDiff", costCenterDiff); + // console.log("LaborAllocationsTable, selectedCostCenter", selectedCostCenter); const { t } = useTranslation(); const onRefresh = async () => { - console.log("LaborAllocationsTable refetch"); + // console.log("LaborAllocationsTable refetch"); return refetch(); }; @@ -43,17 +44,28 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician }) { useEffect(() => { // console.log("LaborAllocationsTable useEffect on [all inputs] change",data?.joblines,data?.adjustments); - if (!!data?.joblines && !!data?.timetickets && !!bodyshop) - setTotals( - CalculateAllocationsTotals( - bodyshop, - data?.joblines, - data?.timetickets, - data?.adjustments - ) + if (!!data?.joblines && !!data?.timetickets && !!bodyshop){ + let temptotals = CalculateAllocationsTotals( + bodyshop, + data?.joblines, + data?.timetickets, + data?.adjustments ); + if(!!selectedCostCenter){ + let tempCostCenterDiff = Math.round( + temptotals.find( + (total) => + total["cost_center"] === selectedCostCenter.label + )?.difference * 10 + ) / 10; + costCenterDiff.current= tempCostCenterDiff; + } + setTotals( + temptotals + ); + } if (!jobId) setTotals([]); - }, [data?.joblines, data?.timetickets, bodyshop, data?.adjustments, jobId]); + }, [data?.joblines, data?.timetickets, bodyshop, data?.adjustments, jobId,selectedCostCenter]); const summary = totals && @@ -70,9 +82,11 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician }) { // console.log("labor summary is:", summary); return ( - + {typeof data !== "undefined" ? ( - + + Labor Allocations + Cost Center @@ -87,9 +101,6 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician }) { - } keyExtractor={(item) => item.cost_center} ItemSeparatorComponent={} renderItem={(object) => ( @@ -147,7 +158,9 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician }) { )} - + + + ) : null} {/* use "totals" for the rows in the table */} {/* use "summary" for the totals at the bottom */} diff --git a/components/time-ticket/screen-time-ticket-clockoff.component.jsx b/components/time-ticket/screen-time-ticket-clockoff.component.jsx index 30ee77e..3fcadd6 100644 --- a/components/time-ticket/screen-time-ticket-clockoff.component.jsx +++ b/components/time-ticket/screen-time-ticket-clockoff.component.jsx @@ -1,16 +1,16 @@ import { Formik } from "formik"; -import React, { useEffect, useState } from "react"; +import React, { useEffect, useState, useRef } 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, Card } from "react-native-paper"; +import { Button, TextInput, Card, Headline, Subheading } 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 { selectBodyshop,selectRestrictClaimableHoursFlag } 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"; @@ -20,6 +20,8 @@ import { timeTicketClockOutStart } from "../../redux/timetickets/timetickets.act import { logImEXEvent } from "../../firebase/firebase.analytics"; import axios from "axios"; import { useNavigation } from "@react-navigation/native"; +import styles from "../styles"; +import StyleRepeater from "../style-repeater/style-repeater"; // import { selectCurrentTimeTicketJobId } from "../../redux/timetickets/timetickets.selectors"; import { QUERY_ACTIVE_TIME_TICKETS } from "../../graphql/timetickets.queries"; @@ -28,6 +30,7 @@ const mapStateToProps = createStructuredSelector({ currentRatesNCostCenters: selectRates, currentBodyshop: selectBodyshop, currentTmTicketJobId: selectCurrentTmTicketJobId, + currentRestrictClaimableHoursFlag: selectRestrictClaimableHoursFlag }); const mapDispatchToProps = (dispatch) => ({ timeTicketClockOutStart, @@ -38,8 +41,19 @@ export function TimeTicketClockOff({ currentRatesNCostCenters, currentBodyshop, currentTmTicketJobId, + currentRestrictClaimableHoursFlag, route, }) { + + const costCenterDiff = useRef(0); + // console.log("TimeTicketClockOff, costCenterDiff :", costCenterDiff); + + + const setCostCenterDiff = (value) => { + countRef.current = val; + console.log(`Button clicked ${countRef.current} times`); + }; + const navigation = useNavigation(); const { timeTicketId } = route.params; // console.log("TimeTicketClockOff, timeTicketId :", timeTicketId); @@ -74,6 +88,15 @@ export function TimeTicketClockOff({ setError({ message: t("timeticketclockoff.errors.missingvalues") }); return; } + // console.log("TimeTicketClockOff, currentRestrictClaimableHoursFlag :", currentRestrictClaimableHoursFlag); + if(!!currentRestrictClaimableHoursFlag){ + // console.log("TimeTicketClockOff, currentRestrictClaimableHoursFlag I am here:", currentRestrictClaimableHoursFlag); + if (values.productivehours > costCenterDiff.current){ + setError({ message: t("timeticketclockoff.errors.hoursenteredmorethanavailable") }); + return; + } + } + const tempcallobj = { variables: { timeticketId: timeTicketId, @@ -117,18 +140,19 @@ export function TimeTicketClockOff({ // console.log("updateTimeticket, result :", result); setLoading(false); if (!!result.errors) { - // console.log("updateTimeticket, result.error :", result.errors); + console.log("updateTimeticket, result.error :", result.errors); setError(JSON.stringify(result.errors)); } else { - // console.log("updateTimeticket, result :", result.data); + console.log("updateTimeticket, result :", result.data); navigation.goBack(); } //if (completedCallback) completedCallback(); }; return ( - - - + + {/* style={localStyles.content}> */} + + - - - - + + ); } diff --git a/graphql/bodyshop.queries.js b/graphql/bodyshop.queries.js index 64cd553..ad6c226 100644 --- a/graphql/bodyshop.queries.js +++ b/graphql/bodyshop.queries.js @@ -14,7 +14,8 @@ export const QUERY_BODYSHOP = gql` features localmediatoken tt_allow_post_to_invoiced - md_responsibility_centers + md_responsibility_centers + tt_enforce_hours_for_tech_console } } `; diff --git a/redux/user/user.selectors.js b/redux/user/user.selectors.js index b6b762a..de0c823 100644 --- a/redux/user/user.selectors.js +++ b/redux/user/user.selectors.js @@ -31,3 +31,15 @@ export const selectSigningIn = createSelector( [selectUser], (user) => user.signingIn ); + +export const selectRestrictClaimableHoursFlag = createSelector( + [selectUser], + (user) => { + if (!user.bodyshop || !user.bodyshop.tt_enforce_hours_for_tech_console) { + console.info("selectRestrictClaimableHoursFlag returning null"); + return null; + } + console.info("selectRestrictClaimableHoursFlag returning :", user.bodyshop.tt_enforce_hours_for_tech_console); + return user.bodyshop.tt_enforce_hours_for_tech_console; + } +); diff --git a/translations/en-US/common.json b/translations/en-US/common.json index 41fe116..5aabbc7 100644 --- a/translations/en-US/common.json +++ b/translations/en-US/common.json @@ -473,7 +473,8 @@ }, "errors": { "nan": "Please make sure all fields have valid values.", - "missingvalues": "Please make sure all fields have a value." + "missingvalues": "Please make sure all fields have a value.", + "hoursenteredmorethanavailable": "The number of hours entered is more than what is available for this cost center." }, "titles": { "clockoff": "Clock Off" diff --git a/translations/es-MX/common.json b/translations/es-MX/common.json index 60f8aa7..145017f 100644 --- a/translations/es-MX/common.json +++ b/translations/es-MX/common.json @@ -473,7 +473,8 @@ }, "errors": { "nan": "", - "missingvalues": "" + "missingvalues": "", + "hoursenteredmorethanavailable": "" }, "titles": { "clockoff": "" diff --git a/translations/fr-CA/common.json b/translations/fr-CA/common.json index d6abc2d..c52eb80 100644 --- a/translations/fr-CA/common.json +++ b/translations/fr-CA/common.json @@ -473,7 +473,8 @@ }, "errors": { "nan": "", - "missingvalues": "" + "missingvalues": "", + "hoursenteredmorethanavailable": "" }, "titles": { "clockoff": "" From 851d8bebe4857d1ae3d24aee9868c8227ca84dc3 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Wed, 7 Jun 2023 14:00:10 -0400 Subject: [PATCH 088/105] Comment out logging statements in application --- components/Selects/select-job-id.jsx | 2 +- redux/employee/employee.sagas.js | 10 ++++----- redux/timetickets/timetickets.sagas.js | 28 ++++++++++++++++++-------- redux/user/user.selectors.js | 4 ++-- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/components/Selects/select-job-id.jsx b/components/Selects/select-job-id.jsx index ef1caf2..efa3e11 100644 --- a/components/Selects/select-job-id.jsx +++ b/components/Selects/select-job-id.jsx @@ -159,7 +159,7 @@ export function JobIdSearchSelect( // }} onChangeText={(search) => { if (search && search !== "") { - console.log("onChangeTextFired!!!!"); + // console.log("onChangeTextFired!!!!"); handleSearch(search); } }} diff --git a/redux/employee/employee.sagas.js b/redux/employee/employee.sagas.js index 9b2fddf..768a543 100644 --- a/redux/employee/employee.sagas.js +++ b/redux/employee/employee.sagas.js @@ -57,7 +57,7 @@ export function* onEmployeeSignInSuccessSaga() { export function* updateEmployeeWithEmployeeId({ payload }) { try { const employeeId = payload.id; - console.log("updateEmployeeWithEmployeeId",employeeId); + // console.log("updateEmployeeWithEmployeeId",employeeId); // logImEXEvent("redux_update_employee_with_employee_id_attempt", employeeId); const result = yield client.query({ query: QUERY_EMPLOYEE_BY_ID, variables: { @@ -73,8 +73,8 @@ export function* updateEmployeeWithEmployeeId({ payload }) { } } catch (error) { yield put(employeeGetRatesFailure(error)); - console.log("Error while getting employee rates.", error); - //Sentry.Native.captureException(error); + // console.log("Error while getting employee rates.", error); + Sentry.Native.captureException(error); } } @@ -104,8 +104,8 @@ export function* getRatesWithEmployeeId({ payload: employeeId }) { } } catch (error) { yield put(employeeGetRatesFailure(error)); - console.log("Error while getting employee rates.", error); - //Sentry.Native.captureException(error); + // console.log("Error while getting employee rates.", error); + Sentry.Native.captureException(error); } } diff --git a/redux/timetickets/timetickets.sagas.js b/redux/timetickets/timetickets.sagas.js index f4de54d..16b925f 100644 --- a/redux/timetickets/timetickets.sagas.js +++ b/redux/timetickets/timetickets.sagas.js @@ -4,7 +4,7 @@ import { timeTicketClockInSuccess, timeTicketClockInFailure, timeTicketClockOutSuccess, - timeTicketClockOutFailure + timeTicketClockOutFailure, } from "./timetickets.actions"; import TimeTicketsActionTypes from "./timetickets.types"; import { client } from "../../graphql/client"; @@ -14,7 +14,6 @@ import { logImEXEvent } from "../../firebase/firebase.analytics"; import { selectCurrentTimeTicket } from "./timetickets.selectors"; import { INSERT_NEW_TIME_TICKET } from "../../graphql/timetickets.queries"; - export function* onCreateTimeTicketStart() { yield takeLatest( TimeTicketsActionTypes.TIME_TICKET_CREATE_START, @@ -24,7 +23,7 @@ export function* onCreateTimeTicketStart() { export function* insertNewTimeTicket({ payload: { timeTicketInput } }) { try { logImEXEvent("redux_insertnewtimeticket_attempt"); - console.log("Saga, TIME_TICKET_CREATE_START :", timeTicketInput); + // console.log("Saga, TIME_TICKET_CREATE_START :", timeTicketInput); //console.loging // console.log("Saga", employeeId, pin, pin); const timeTicket = yield select(selectCurrentTimeTicket); @@ -73,13 +72,18 @@ export function* insertNewTimeTicket({ payload: { timeTicketInput } }) { } export function* onClockOutStart() { - yield takeLatest(TimeTicketsActionTypes.TIME_TICKET_CLOCKOUT_START,clockOutStart); + yield takeLatest( + TimeTicketsActionTypes.TIME_TICKET_CLOCKOUT_START, + clockOutStart + ); } export function* clockOutStart({ payload: { timeTicketInput } }) { try { logImEXEvent("redux_clockOutStart_attempt"); //console.loging - console.log("Saga, clockOutStart :", timeTicketInput); + + // console.log("Saga, clockOutStart :", timeTicketInput); + // const timeTicket = yield select(selectCurrentTimeTicket); // const response = yield call(axios.post, "/tech/login", { // shopid: bodyshop.id, @@ -125,16 +129,24 @@ export function* clockOutStart({ payload: { timeTicketInput } }) { } } export function* onClockInStart() { - yield takeLatest(TimeTicketsActionTypes.TIME_TICKET_CLOCKIN_START,clockInStart); + yield takeLatest( + TimeTicketsActionTypes.TIME_TICKET_CLOCKIN_START, + clockInStart + ); } export function* clockInStart({ payload: { timeTicketInput } }) { try { logImEXEvent("redux_clockInStart_attempt"); - console.log("Saga, clockInStart :", timeTicketInput); + + // console.log("Saga, clockInStart :", timeTicketInput); } catch (error) { yield put(timeTicketClockInFailure(error)); } } export function* timeTicketsSagas() { - yield all([call(onCreateTimeTicketStart),call(onClockOutStart),call(onClockInStart)]); + yield all([ + call(onCreateTimeTicketStart), + call(onClockOutStart), + call(onClockInStart), + ]); } diff --git a/redux/user/user.selectors.js b/redux/user/user.selectors.js index de0c823..fe3fdec 100644 --- a/redux/user/user.selectors.js +++ b/redux/user/user.selectors.js @@ -36,10 +36,10 @@ export const selectRestrictClaimableHoursFlag = createSelector( [selectUser], (user) => { if (!user.bodyshop || !user.bodyshop.tt_enforce_hours_for_tech_console) { - console.info("selectRestrictClaimableHoursFlag returning null"); + // console.info("selectRestrictClaimableHoursFlag returning null"); return null; } - console.info("selectRestrictClaimableHoursFlag returning :", user.bodyshop.tt_enforce_hours_for_tech_console); + // console.info("selectRestrictClaimableHoursFlag returning :", user.bodyshop.tt_enforce_hours_for_tech_console); return user.bodyshop.tt_enforce_hours_for_tech_console; } ); From 9828ee3da082d3bc5f029838c411be225354b4fa Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 8 Jun 2023 15:28:03 -0400 Subject: [PATCH 089/105] updated styling and display jobslist above clockin --- components/Selects/select-cost-center.jsx | 2 +- components/Selects/select-job-id.jsx | 5 +- .../labor-allocations-table.component.jsx | 6 +- .../screen-time-ticket-browser.component.jsx | 234 ++++++++++++------ components/styles.js | 19 ++ .../clockedin-list-item.component.jsx | 10 +- .../screen-time-ticket-clockoff.component.jsx | 155 +++++++----- .../screen-time-ticket-create.component.jsx | 218 ++++++++-------- translations/en-US/common.json | 2 +- 9 files changed, 407 insertions(+), 244 deletions(-) diff --git a/components/Selects/select-cost-center.jsx b/components/Selects/select-cost-center.jsx index 581f9a0..7c9b0df 100644 --- a/components/Selects/select-cost-center.jsx +++ b/components/Selects/select-cost-center.jsx @@ -85,7 +85,7 @@ const styles = StyleSheet.create({ height: 48, borderColor: "gray", borderWidth: 0.5, - borderRadius: 8, + borderRadius: 4, paddingHorizontal: 8, }, icon: { diff --git a/components/Selects/select-job-id.jsx b/components/Selects/select-job-id.jsx index efa3e11..7846b04 100644 --- a/components/Selects/select-job-id.jsx +++ b/components/Selects/select-job-id.jsx @@ -173,7 +173,8 @@ export default connect(null, null)(JobIdSearchSelect); const styles = StyleSheet.create({ container: { - padding: 16, + marginVertical: 4, + marginHorizontal: 16, justifyContent: "center", alignContent: "center", }, @@ -181,7 +182,7 @@ const styles = StyleSheet.create({ height: 50, borderColor: "gray", borderWidth: 0.5, - borderRadius: 8, + borderRadius: 4, paddingHorizontal: 8, }, icon: { diff --git a/components/labor-allocations-table/labor-allocations-table.component.jsx b/components/labor-allocations-table/labor-allocations-table.component.jsx index 8a44a75..d26c06f 100644 --- a/components/labor-allocations-table/labor-allocations-table.component.jsx +++ b/components/labor-allocations-table/labor-allocations-table.component.jsx @@ -82,12 +82,11 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician,costCenterDi // console.log("labor summary is:", summary); return ( - + {typeof data !== "undefined" ? ( - Labor Allocations + - Cost Center Hours Total @@ -97,7 +96,6 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician,costCenterDi Difference - { // console.log("handleFinish called in ScreenTimeTicketBrowser"); - setLoading(true); + setLoadingClockIn(true); setError(null); const theTime = (await axios.post("/utils/time")).data; @@ -78,7 +100,7 @@ export function ScreenTimeTicketBrowser({ // console.log("have all values"); } else { // console.log("missing values!"); - setLoading(false); + setLoadingClockIn(false); setError({ message: t("timeticketbrowser.errors.missingvalues") }); return; } @@ -112,7 +134,7 @@ export function ScreenTimeTicketBrowser({ // console.info("INSERT_NEW_TIME_TICKET, variables for clockin. : ",tempVariablesObj?.variables?.timeTicketInput[0] ); const result = await insertTimeTicket(tempVariablesObj); // console.log("insertTimeTicket, result :", result); - setLoading(false); + setLoadingClockIn(false); if (!!result.errors) { // console.log("insertTimeTicket, result.error :", result.errors); setError(JSON.stringify(result.errors)); @@ -122,81 +144,153 @@ export function ScreenTimeTicketBrowser({ setCurrentSCC(null); } }; + const onRefresh = useCallback(() => { setRefreshing(true); + refetch(); setTimeout(() => { setRefreshing(false); - }, 2000); + }, 1000); }, []); + const [itemState, setItemState] = useState({ + title: t("employeeclockedinlist.labels.alreadyclockedon"), + data: null, + content: null, + }); + + const { loadingATT, errorATT, dataATT, refetch } = useQuery( + QUERY_ACTIVE_TIME_TICKETS, + { + variables: { + employeeId: currentEmployee?.technician?.id, + }, + skip: !currentEmployee?.technician, + onCompleted: (dataATT) => { + if (!!dataATT && dataATT?.timetickets) { + setItemState((itemState) => ({ + ...itemState, + data: dataATT?.timetickets, + })); + } + }, + onRefresh: { onRefresh }, + } + ); + + if (loadingATT) { + // console.log("loadingATT : "); + setItemState((itemState) => ({ + ...itemState, + content: , + })); + return; + } + if (errorATT) { + // console.error("ErrorATT : ",errorATT); + setItemState((itemState) => ({ + ...itemState, + content: , + })); + return; + } + // console.log({ itemState: !!itemState }); + return ( - - } - > - - - } - /> - - {currentEmployeeFullName && ( - {currentEmployeeFullName} - )} - - - - - // - // - // } - /> - - - - {error && error?.message ? ( - - ) : null} - - - - - - - - + + + } + /> + + {currentEmployeeFullName && ( + {currentEmployeeFullName} + )} + + + } + data={!!itemState ? [itemState] : null} + renderItem={({ item }) => ( + + )} + ListFooterComponent={ + + + // + // + // } + /> + + + + {error && error?.message ? ( + + ) : null} + + + + } + refreshControl={ + + } + /> + ); } +const MyItem = ({ itemState, style }) => { + const items = itemState?.data; + return ( + + + + {!!items ? ( + items.map((item) => ) + ) : !!itemState.content ? ( + itemState.content + ) : ( + No Data + )} + + + ); +}; + const localStyles = StyleSheet.create({ content: { display: "flex", flex: 2, }, + localCardStyle: { + margin: 4, + }, }); export default connect( diff --git a/components/styles.js b/components/styles.js index 3ca0bee..6aebb5f 100644 --- a/components/styles.js +++ b/components/styles.js @@ -9,4 +9,23 @@ export default StyleSheet.create({ display: "flex", flex: 1, }, + buttonBasicOutlined: { + marginVertical: 4, + marginHorizontal: 16, + justifyContent: "center", + alignContent: "center", + borderColor: "gray", + borderWidth: 0.8, + borderRadius: 4, + }, + buttonFatOutlined: { + marginVertical: 4, + marginHorizontal: 16, + height: 48, + justifyContent: "center", + alignContent: "center", + borderColor: "gray", + borderWidth: 0.8, + borderRadius: 4, + } }); diff --git a/components/time-ticket-items/clockedin-list-item.component.jsx b/components/time-ticket-items/clockedin-list-item.component.jsx index 7505208..36b0272 100644 --- a/components/time-ticket-items/clockedin-list-item.component.jsx +++ b/components/time-ticket-items/clockedin-list-item.component.jsx @@ -6,13 +6,14 @@ import { connect } from "react-redux"; import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component"; import { DateTimeFormatter } from "../../util/DateFormater"; import { setTmTicketJobId } from "../../redux/app/app.actions"; +import styles from "../styles"; const mapDispatchToProps = (dispatch) => ({ setTmTicketJobIdRedux: (jobId) => dispatch(setTmTicketJobId(jobId)), }); export function ClockedinListItem({ setTmTicketJobIdRedux, ticket }) { - // console.log("makeNavToTimeTicketClockOff, handleRefresh:"); + // console.log("ClockedinListItem, ticket:",ticket); const { t } = useTranslation(); const navigation = useNavigation(); @@ -28,7 +29,7 @@ export function ClockedinListItem({ setTmTicketJobIdRedux, ticket }) { ); return ( - + - - diff --git a/components/time-ticket/screen-time-ticket-clockoff.component.jsx b/components/time-ticket/screen-time-ticket-clockoff.component.jsx index 3fcadd6..46ab509 100644 --- a/components/time-ticket/screen-time-ticket-clockoff.component.jsx +++ b/components/time-ticket/screen-time-ticket-clockoff.component.jsx @@ -4,13 +4,22 @@ 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, Card, Headline, Subheading } from "react-native-paper"; -import CostCenterSelect from "../Selects/select-cost-center"; +import { + Button, + TextInput, + Card, + Headline, + Subheading, +} from "react-native-paper"; +import CostCenterSelect from "../Selects/select-cost-center"; import { selectCurrentEmployee, selectRates, } from "../../redux/employee/employee.selectors"; -import { selectBodyshop,selectRestrictClaimableHoursFlag } from "../../redux/user/user.selectors"; +import { + selectBodyshop, + selectRestrictClaimableHoursFlag, +} 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"; @@ -30,7 +39,7 @@ const mapStateToProps = createStructuredSelector({ currentRatesNCostCenters: selectRates, currentBodyshop: selectBodyshop, currentTmTicketJobId: selectCurrentTmTicketJobId, - currentRestrictClaimableHoursFlag: selectRestrictClaimableHoursFlag + currentRestrictClaimableHoursFlag: selectRestrictClaimableHoursFlag, }); const mapDispatchToProps = (dispatch) => ({ timeTicketClockOutStart, @@ -44,14 +53,12 @@ export function TimeTicketClockOff({ currentRestrictClaimableHoursFlag, route, }) { - const costCenterDiff = useRef(0); // console.log("TimeTicketClockOff, costCenterDiff :", costCenterDiff); - const setCostCenterDiff = (value) => { countRef.current = val; - console.log(`Button clicked ${countRef.current} times`); + // console.log(`Button clicked ${countRef.current} times`); }; const navigation = useNavigation(); @@ -64,8 +71,9 @@ export function TimeTicketClockOff({ const [error, setError] = useState(null); const [currentSCC, setCurrentSCC] = useState(null); - const [updateTimeticket] = useMutation(UPDATE_TIME_TICKET, - {refetchQueries: ["QUERY_ACTIVE_TIME_TICKETS"]}); + const [updateTimeticket] = useMutation(UPDATE_TIME_TICKET, { + refetchQueries: ["QUERY_ACTIVE_TIME_TICKETS"], + }); const handleFinish = async (values) => { logImEXEvent("TimeTicketClockOff_handleFinish"); @@ -75,7 +83,7 @@ export function TimeTicketClockOff({ !!values.productivehours && !!currentSCC?.value ) { - if (isNaN(values.actualhours)|isNaN(values.productivehours)) { + if (isNaN(values.actualhours) | isNaN(values.productivehours)) { // console.log("actual hours is NAN!"); setLoading(false); setError({ message: t("timeticketclockoff.errors.nan") }); @@ -85,16 +93,18 @@ export function TimeTicketClockOff({ // console.log("all have values:"); } else { // console.log("missing values!"); - setError({ message: t("timeticketclockoff.errors.missingvalues") }); + setError({ message: t("timeticketclockoff.errors.missingvalues") }); return; } // console.log("TimeTicketClockOff, currentRestrictClaimableHoursFlag :", currentRestrictClaimableHoursFlag); - if(!!currentRestrictClaimableHoursFlag){ + if (!!currentRestrictClaimableHoursFlag) { // console.log("TimeTicketClockOff, currentRestrictClaimableHoursFlag I am here:", currentRestrictClaimableHoursFlag); - if (values.productivehours > costCenterDiff.current){ - setError({ message: t("timeticketclockoff.errors.hoursenteredmorethanavailable") }); + if (values.productivehours > costCenterDiff.current) { + setError({ + message: t("timeticketclockoff.errors.hoursenteredmorethanavailable"), + }); return; - } + } } const tempcallobj = { @@ -140,65 +150,80 @@ export function TimeTicketClockOff({ // console.log("updateTimeticket, result :", result); setLoading(false); if (!!result.errors) { - console.log("updateTimeticket, result.error :", result.errors); + // console.log("updateTimeticket, result.error :", result.errors); setError(JSON.stringify(result.errors)); } else { - console.log("updateTimeticket, result :", result.data); + // console.log("updateTimeticket, result :", result.data); navigation.goBack(); } //if (completedCallback) completedCallback(); }; return ( - - {/* style={localStyles.content}> */} + + {/* style={localStyles.content}> */} - - - {({ handleChange, handleBlur, handleSubmit, values }) => ( - - - - - {error ? : null} - - - )} - + + + + {({ handleChange, handleBlur, handleSubmit, values }) => ( + + + + + {error ? : null} + + + )} + + - + + + ); diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index cc81872..d2da332 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -4,14 +4,14 @@ 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 { Button, TextInput, Card } from "react-native-paper"; +import CostCenterSelect from "../Selects/select-cost-center"; import { JobIdSearchSelect } from "../Selects/select-job-id"; import DateTimePickerModal from "react-native-modal-datetime-picker"; import { selectCurrentEmployee, selectRates, - selectEmployeeFullName + selectEmployeeFullName, } from "../../redux/employee/employee.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; import { useCallback } from "react"; @@ -26,11 +26,14 @@ import { logImEXEvent } from "../../firebase/firebase.analytics"; import moment from "moment"; import { useNavigation } from "@react-navigation/native"; +import styles from "../styles"; +import StyleRepeater from "../style-repeater/style-repeater"; + const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, currentRatesNCostCenters: selectRates, currentBodyshop: selectBodyshop, - currentEmployeeFullName: selectEmployeeFullName + currentEmployeeFullName: selectEmployeeFullName, }); // const mapDispatchToProps = (dispatch) => ({}); @@ -38,7 +41,7 @@ export function TimeTicketCreate({ currentEmployee, currentRatesNCostCenters, currentBodyshop, - currentEmployeeFullName + currentEmployeeFullName, }) { const navigation = useNavigation(); const { t } = useTranslation(); @@ -95,7 +98,7 @@ export function TimeTicketCreate({ } else { // console.log("missing values!"); setLoading(false); - setError({ message: t("createtimeticket.errors.missingvalues")}); + setError({ message: t("createtimeticket.errors.missingvalues") }); return; } @@ -172,95 +175,110 @@ export function TimeTicketCreate({ setLoading(false); }; return ( - - - - {({ handleChange, handleBlur, handleSubmit, values }) => ( - - - {/* Below will be replaced with a Date Picker*/} - {/* */} - - - - - - - {error ? : null} - - - )} - - + + + {/* */} + + + + {({ handleChange, handleBlur, handleSubmit, values }) => ( + + + {/* Below will be replaced with a Date Picker*/} + {/* */} + + + + + + + {error ? : null} + + + )} + + + {/* Below is for list of jobs/tickets */} - - - - + {/* */} + + + + ); } @@ -274,16 +292,22 @@ const localStyles = StyleSheet.create({ }, topContainer: {}, bottomContainer: {}, - input: {}, + input: { + marginVertical: 4, + marginHorizontal: 16, + height: 48, + justifyContent: "center", + alignContent: "center", + borderWidth: 0.8, + }, dateButton: { marginVertical: 4, marginHorizontal: 16, height: 48, justifyContent: "center", alignContent: "center", - borderColor: "blue", + borderColor: "gray", borderWidth: 0.8, - flex: 1, }, textForButton: { flex: 1, diff --git a/translations/en-US/common.json b/translations/en-US/common.json index 5aabbc7..40bf6d6 100644 --- a/translations/en-US/common.json +++ b/translations/en-US/common.json @@ -496,7 +496,7 @@ }, "employeeclockedinlist": { "labels": { - "alreadyclockedon": "You are already clocked in to the following job(s):" + "alreadyclockedon": "Clocked into job(s)" } }, "clockedinlistitem": { From 669b11b2d2ce0a08b7fc3b1a8b4b5b1e9c792277 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 8 Jun 2023 15:54:18 -0400 Subject: [PATCH 090/105] updated small style changes --- .../screen-time-ticket-browser.component.jsx | 12 +++++++++--- translations/en-US/common.json | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) 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 6bffdf5..76ff2f5 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 @@ -47,8 +47,8 @@ import { logImEXEvent } from "../../firebase/firebase.analytics"; import StyleRepeater from "../style-repeater/style-repeater"; import { useTranslation } from "react-i18next"; import ClockedinListItem from "../time-ticket-items/clockedin-list-item.component"; -import SignOutButton from "../Buttons/employee-sign-out-button.component"; -import AddTimeTicketButton from "../Buttons/create-time-ticket-button.component"; +import SignOutButton from "../Buttons/employee-sign-out-button.component"; +import AddTimeTicketButton from "../Buttons/create-time-ticket-button.component"; const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, @@ -246,6 +246,12 @@ export function ScreenTimeTicketBrowser({ {error && error?.message ? ( ) : null} + + - + } refreshControl={ diff --git a/translations/en-US/common.json b/translations/en-US/common.json index 40bf6d6..1ca773b 100644 --- a/translations/en-US/common.json +++ b/translations/en-US/common.json @@ -335,7 +335,7 @@ }, "labels": { "loggedinemployee": "Logged in Employee", - "clockintojob": "Clock Into Job" + "clockintojob": "Clock In" }, "errors": { "missingvalues": "Please make sure all fields have a value." From 36575081418d2f4418847bcc316289f3ff95e6af Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Fri, 9 Jun 2023 10:11:01 -0400 Subject: [PATCH 091/105] Change PIN field on Employee Log in --- .../screen-employee-sign-in.component.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/components/screen-employee-sign-in/screen-employee-sign-in.component.jsx b/components/screen-employee-sign-in/screen-employee-sign-in.component.jsx index 9c29066..4f29785 100644 --- a/components/screen-employee-sign-in/screen-employee-sign-in.component.jsx +++ b/components/screen-employee-sign-in/screen-employee-sign-in.component.jsx @@ -67,6 +67,7 @@ const signingErrorMsg = signingError ? ( {signingErrorMsg} - - )} - - - - - - - + + + + {({ handleChange, handleBlur, handleSubmit, values }) => ( + + + + + {error ? ( + + ) : null} + + + )} + + + + } + data={null} + renderItem={null} + ListFooterComponent={ + + } + refreshControl={ + + } + />
); } @@ -260,4 +285,7 @@ const localStyles = StyleSheet.create({ height: 48, fontSize: 16, }, + localCardStyle: { + margin: 4, + }, }); diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index d2da332..6ba5462 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -1,6 +1,6 @@ import { Formik } from "formik"; -import React, { useState } from "react"; -import { StyleSheet, Text, View, ScrollView } from "react-native"; +import React, { useRef, useState } from "react"; +import { StyleSheet, Text, View, ScrollView, RefreshControl } from "react-native"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; @@ -13,7 +13,10 @@ import { selectRates, selectEmployeeFullName, } from "../../redux/employee/employee.selectors"; -import { selectBodyshop } from "../../redux/user/user.selectors"; +import { + selectBodyshop, + selectRestrictClaimableHoursFlag, +} from "../../redux/user/user.selectors"; import { useCallback } from "react"; // import LaborAllocationsTable from "../labor-allocations-table/labor-allocations-table.component"; import LaborAllocationsTable from "../labor-allocations-table/labor-allocations-table.component"; @@ -28,12 +31,14 @@ import { useNavigation } from "@react-navigation/native"; import styles from "../styles"; import StyleRepeater from "../style-repeater/style-repeater"; +import { FlatList } from "react-native"; const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, currentRatesNCostCenters: selectRates, currentBodyshop: selectBodyshop, currentEmployeeFullName: selectEmployeeFullName, + currentRestrictClaimableHoursFlag: selectRestrictClaimableHoursFlag, }); // const mapDispatchToProps = (dispatch) => ({}); @@ -42,10 +47,13 @@ export function TimeTicketCreate({ currentRatesNCostCenters, currentBodyshop, currentEmployeeFullName, + currentRestrictClaimableHoursFlag, }) { + const costCenterDiff = useRef(0); const navigation = useNavigation(); const { t } = useTranslation(); const [loading, setLoading] = useState(false); + const [loadingCreate, setLoadingCreate] = useState(false); const [error, setError] = useState(null); const [isDatePickerVisible, setDatePickerVisibility] = useState(false); @@ -72,7 +80,7 @@ export function TimeTicketCreate({ logImEXEvent("handleFinish_called_in_TimeTicketCreate"); // console.log("handleFinish called in TimeTicketCreate"); setError(null); - setLoading(true); + setLoadingCreate(true); // console.log("insertTicket, currentSCC :", currentSCC); // console.log("insertTicket, currentSCC :", currentSJobId); @@ -89,7 +97,7 @@ export function TimeTicketCreate({ ) { if (isNaN(values.actualhours) | isNaN(values.productivehours)) { // console.log("actual hours is NAN!"); - setLoading(false); + setLoadingCreate(false); setError({ message: t("createtimeticket.errors.nan") }); return; } @@ -97,11 +105,22 @@ export function TimeTicketCreate({ // console.log("have all values"); } else { // console.log("missing values!"); - setLoading(false); + setLoadingCreate(false); setError({ message: t("createtimeticket.errors.missingvalues") }); return; } + if (!!currentRestrictClaimableHoursFlag) { + // console.log("TimeTicketClockOff, currentRestrictClaimableHoursFlag I am here:", currentRestrictClaimableHoursFlag); + if (values.productivehours > costCenterDiff.current) { + setLoadingCreate(false); + setError({ + message: t("timeticketclockoff.errors.hoursenteredmorethanavailable"), + }); + return; + } + } + // if (date2) console.log("rate :", currentRatesNCostCenters && currentSCC?.value ? currentRatesNCostCenters.filter((r) => r.cost_center === currentSCC?.value)[0].rate : null);//2023-05-16T16:45:27.154Z // if (date2) console.log("bodyshopid : ", currentBodyshop.id); // if (date2) console.log("moment(date2).format(YYYY-MM-DD)", moment(date2).format("YYYY-MM-DD")); @@ -155,7 +174,7 @@ export function TimeTicketCreate({ // console.log(" result : ", result); // //after call results are retuning add handling below for cases // console.log("insertTicket, result :", result?.data?.insert_timetickets?.returning[0]); - setLoading(false); + setLoadingCreate(false); if (!!result.errors) { // console.log("insertTicket, result.error :", result.errors); setError(JSON.stringify(result.errors)); @@ -166,119 +185,140 @@ export function TimeTicketCreate({ // if (completedCallback) completedCallback(); }; - const handleMutationError = (error) => { - // setEnterAgain(false); - console.log("insertTicket, result.error :", error); - setError( - error?.message ? JSON.stringify(error?.message) : JSON.stringify(error) - ); - setLoading(false); - }; + // const handleMutationError = (error) => { + // // setEnterAgain(false); + // console.log("insertTicket, result.error :", error); + // setError( + // error?.message ? JSON.stringify(error?.message) : JSON.stringify(error) + // ); + // setLoading(false); + // }; + + const onRefresh = useCallback(() => { + setLoading(true); + // refetch(); + setTimeout(() => { + setLoading(false); + }, 1000); + }, []); + return ( - - {/* */} - - - - {({ handleChange, handleBlur, handleSubmit, values }) => ( - - - {/* Below will be replaced with a Date Picker*/} - {/* */} - - - - - - - {error ? : null} - - - )} - - - - {/* Below is for list of jobs/tickets */} - {/* */} - - - - + + + + {({ handleChange, handleBlur, handleSubmit, values }) => ( + + + + + + + + + {error ? ( + + ) : null} + + + )} + + + + } + data={null} + renderItem={null} + ListFooterComponent={ + + } + refreshControl={ + + } + /> ); } @@ -320,4 +360,7 @@ const localStyles = StyleSheet.create({ height: 48, fontSize: 16, }, + localCardStyle: { + margin: 4, + }, }); From b2f8c4cd95a6a135105946ce4bd8b856a4fc8d8a Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Tue, 13 Jun 2023 15:51:51 -0400 Subject: [PATCH 094/105] Fix Android Keyboard display issue --- components/Selects/select-cost-center.jsx | 10 +- components/Selects/select-job-id.jsx | 45 +++--- .../keyboards/KeyboardAvoidingComponent.js | 31 ++++ .../screen-time-ticket-browser.component.jsx | 136 +++++++++--------- 4 files changed, 135 insertions(+), 87 deletions(-) create mode 100644 components/keyboards/KeyboardAvoidingComponent.js diff --git a/components/Selects/select-cost-center.jsx b/components/Selects/select-cost-center.jsx index 7c9b0df..7a4bd99 100644 --- a/components/Selects/select-cost-center.jsx +++ b/components/Selects/select-cost-center.jsx @@ -53,7 +53,7 @@ export function CostCenterSelect(props) { inputSearchStyle={styles.inputSearchStyle} iconStyle={styles.iconStyle} - maxHeight={300} + maxHeight={200} labelField="label" valueField="value" placeholder={!isFocus ? t("selectcostcenter.labels.placeholder") : t("selectcostcenter.labels.selectedplaceholder")} @@ -82,7 +82,7 @@ const styles = StyleSheet.create({ alignContent: "center", }, dropdown: { - height: 48, + height: 50, borderColor: "gray", borderWidth: 0.5, borderRadius: 4, @@ -101,10 +101,10 @@ const styles = StyleSheet.create({ fontSize: 14, }, placeholderStyle: { - fontSize: 16, + fontSize: 14, }, selectedTextStyle: { - fontSize: 16, + fontSize: 14, }, iconStyle: { width: 20, @@ -112,6 +112,6 @@ const styles = StyleSheet.create({ }, inputSearchStyle: { height: 40, - fontSize: 16, + fontSize: 14, }, }); diff --git a/components/Selects/select-job-id.jsx b/components/Selects/select-job-id.jsx index 7846b04..92451ce 100644 --- a/components/Selects/select-job-id.jsx +++ b/components/Selects/select-job-id.jsx @@ -94,21 +94,27 @@ export function JobIdSearchSelect( }, [data, idData]); useEffect(() => { - // 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++) { - selectDataArray.push({ - value: theOptions[i].id, - label: `${clm_no && theOptions[i].clm_no ? `${theOptions[i].clm_no} | ` : ""}${ + if (typeof theOptions !== "undefined") { + // 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++) { + selectDataArray.push({ + value: theOptions[i].id, + 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 || ""} ${ + } | ${OwnerNameDisplayFunction(theOptions[i])} | ${ + theOptions[i].v_model_yr || "" + } ${theOptions[i].v_make_desc || ""} ${ theOptions[i].v_model_desc || "" }`, - }); + }); + } + setSelectorData(selectDataArray); } - setSelectorData(selectDataArray); }, [theOptions]); // useEffect(() => { @@ -128,7 +134,7 @@ export function JobIdSearchSelect( inputSearchStyle={styles.inputSearchStyle} iconStyle={styles.iconStyle} search - maxHeight={300} + maxHeight={200} labelField="label" valueField="value" placeholder={!isFocus ? t("selectjobid.labels.placeholder") : t("selectjobid.labels.selectedplaceholder")} @@ -137,7 +143,14 @@ export function JobIdSearchSelect( onBlur={() => setIsFocus(false)} data={selectorData} value={props.currentValue?.value} //{selectedvalue} - onChange={(item) => props.onJobSelected(item)}//TODO: add setIsFocus(false); to this + onChange={(item) => { + // console.log("onChange Fired!!!!"); + props.onJobSelected(item); + setIsFocus(false); + }} + + + //TODO: add setIsFocus(false); to this // { // console.log("onValueSelected!!!!"); // // (item) => {onJobSelected(item.value)}; @@ -198,10 +211,10 @@ const styles = StyleSheet.create({ fontSize: 14, }, placeholderStyle: { - fontSize: 16, + fontSize: 14, }, selectedTextStyle: { - fontSize: 16, + fontSize: 14, }, iconStyle: { width: 20, @@ -209,6 +222,6 @@ const styles = StyleSheet.create({ }, inputSearchStyle: { height: 40, - fontSize: 16, + fontSize: 14, }, }); diff --git a/components/keyboards/KeyboardAvoidingComponent.js b/components/keyboards/KeyboardAvoidingComponent.js new file mode 100644 index 0000000..c845f39 --- /dev/null +++ b/components/keyboards/KeyboardAvoidingComponent.js @@ -0,0 +1,31 @@ +import { View, Text, Platform } from "react-native"; +import React from "react"; +import { KeyboardAvoidingView } from "react-native"; +import { StyleSheet } from "react-native"; +import { TouchableWithoutFeedback } from "react-native"; +import { Keyboard } from "react-native"; + +const KeyboardAvoidingComponent = ({ children }) => { + return ( + + {/* */} + {children} + {/* */} + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + inner: { + flex: 1, + }, +}); + +export default KeyboardAvoidingComponent; 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 56f8dde..91fe99c 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 @@ -50,6 +50,8 @@ import ClockedinListItem from "../time-ticket-items/clockedin-list-item.componen import SignOutButton from "../Buttons/employee-sign-out-button.component"; import AddTimeTicketButton from "../Buttons/create-time-ticket-button.component"; +import KeyboardAvoidingComponent from "../keyboards/KeyboardAvoidingComponent"; + const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, loaderGettingRates: selectGettingRates, @@ -198,75 +200,77 @@ export function ScreenTimeTicketBrowser({ return ( - - } - /> - - {currentEmployeeFullName && ( - {currentEmployeeFullName} - )} - - - } - data={!!itemState ? [itemState] : null} - renderItem={({ item }) => ( - - )} - ListFooterComponent={ - - - // - // - // } - /> - - + + } /> - + {currentEmployeeFullName && ( + {currentEmployeeFullName} + )} + + + } + data={!!itemState ? [itemState] : null} + renderItem={({ item }) => ( + + )} + ListFooterComponent={ + + + // + // + // } /> - {error && error?.message ? ( - - ) : null} - - - - - - } - refreshControl={ - - } - /> + + + + } + refreshControl={ + + } + /> + ); } From 408794cfe0c8ca0629d80afeb56c79097dd0cb38 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 13 Jul 2023 17:12:53 -0400 Subject: [PATCH 095/105] adding non hooked up modal --- components/Modals/JobSearchAndSelectModal.jsx | 210 ++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 components/Modals/JobSearchAndSelectModal.jsx diff --git a/components/Modals/JobSearchAndSelectModal.jsx b/components/Modals/JobSearchAndSelectModal.jsx new file mode 100644 index 0000000..24fafd1 --- /dev/null +++ b/components/Modals/JobSearchAndSelectModal.jsx @@ -0,0 +1,210 @@ +import { useQuery } from "@apollo/client"; +import { Ionicons } from "@expo/vector-icons"; +import React from "react"; +import { useTranslation } from "react-i18next"; +import { FlatList, RefreshControl, View } from "react-native"; +import { Button, List, Modal, Portal, Searchbar } from "react-native-paper"; +import { connect } from "react-redux"; +// import { createStructuredSelector } from "reselect"; +import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries"; +// import { setCameraJob, setCameraJobId } from "../../redux/app/app.actions"; +// import { +// selectCurrentCameraJob, +// selectCurrentCameraJobId, +// } from "../../redux/app/app.selectors"; +// import { selectBodyshop } from "../../redux/user/user.selectors"; +import ErrorDisplay from "../error-display/error-display.component"; +import LoadingDisplay from "../loading-display/loading-display.component"; + +// const mapStateToProps = createStructuredSelector({ +// cameraJobId: selectCurrentCameraJobId, +// cameraJob: selectCurrentCameraJob, +// }); + +// const mapDispatchToProps = (dispatch) => ({ +// setCameraJobId: (id) => dispatch(setCameraJobId(id)), +// setCameraJob: (job) => dispatch(setCameraJob(job)), +// }); + +export function JobSearchAndSelectModal( + props, +// cameraJobId, +// setCameraJobId, +// cameraJob, +// setCameraJob, +) { + const jobSrchNotExported = + props?.notExported !== undefined ? props.notExported : true; + const jobSrchNotInvoiced = + props?.notInvoiced !== undefined ? props.notInvoiced : false; + const jobSrchConvertedOnly = + props?.convertedOnly !== undefined ? props.convertedOnly : false; + + const jobSrchCurrentValue = props?.currentValue !== undefined ? props.currentValue : { id: "temp", ro_number: "Temporary Storage" }; + const jobSrchOnSetCurrentValue = props?.onSetCurrentValue !== undefined ? props.onSetCurrentValue : (e) => { console.info("onSetCurrentValue was called",e);}; + const jobSrchCurrentValueId = props?.currentValueId !== undefined ? props.currentValueId : "temp"; + const jobSrchOnSetCurrentValueId = props?.onSetCurrentValueId !== undefined ? props.onSetCurrentValueId : () => { console.info("onSetCurrentValueId was called"); }; + + console.log(" "); + console.log("*****JobSearchAndSelectModal*****"); + console.log("props:", props);//works +// console.log("notExported:", jobSrchNotExported);//works +// console.log("notInvoiced:", jobSrchNotInvoiced);//works +// console.log("convertedOnly:", jobSrchConvertedOnly);//works + console.log("jobSrchCurrentValue:", jobSrchCurrentValue); //{"id": "temp", "ro_number": "Temporary Storage"} + console.log("jobSrchOnSetCurrentValue:", jobSrchOnSetCurrentValue); + console.log("jobSrchCurrentValueId:", jobSrchCurrentValueId); //temp will be currentValue + console.log("jobSrchOnSetCurrentValueId:", jobSrchOnSetCurrentValueId); // will be onSetCurrentValue + + + const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, { + fetchPolicy: "cache-and-network", + variables: { + statuses: false || ["Open", "Open*"], + }, + }); + const { t } = useTranslation(); + const [visible, setVisible] = React.useState(false); + const [searchQuery, setSearchQuery] = React.useState(""); + if (loading) return ; + if (error) return ; + + const showModal = () => setVisible(true); + const hideModal = () => setVisible(false); + + const onRefresh = async () => { + console.log("onRefresh was called"); + return refetch(); + }; + + const onChangeSearch = (query) => setSearchQuery(query); + + const jobs = data + ? searchQuery === "" + ? data.jobs + : data.jobs.filter( + (j) => + (j.ro_number || "") + .toString() + .toLowerCase() + .includes(searchQuery.toLowerCase()) || + (j.ownr_co_nm || "") + .toLowerCase() + .includes(searchQuery.toLowerCase()) || + (j.ownr_fn || "") + .toLowerCase() + .includes(searchQuery.toLowerCase()) || + (j.ownr_ln || "") + .toLowerCase() + .includes(searchQuery.toLowerCase()) || + (j.plate_no || "") + .toLowerCase() + .includes(searchQuery.toLowerCase()) || + (j.v_model_desc || "") + .toLowerCase() + .includes(searchQuery.toLowerCase()) || + (j.v_make_desc || "") + .toLowerCase() + .includes(searchQuery.toLowerCase()) + ) + : []; + + return ( + <> + + + + + + + + } + data={[{ id: "temp", ro_number: "Temporary Storage" }, ...jobs]} + keyExtractor={(item) => item.id} + renderItem={(object) => ( + { + //setCameraJob(object.item); + //setCameraJobId(object.item.id); + jobSrchOnSetCurrentValue(object.item); + jobSrchOnSetCurrentValueId(object.item.id); + hideModal(); + setSearchQuery(""); + }} + left={() => { + if (object.item.id !== jobSrchCurrentValueId) return null; + return ( + + ); + }} + titleStyle={{ + ...(object.item.id === jobSrchCurrentValueId + ? { color: "dodgerblue" } + : {}), + }} + title={`${ + object.item.ro_number ? `${object.item.ro_number} ` : `` + }${object.item.ownr_fn || ""} ${object.item.ownr_ln || ""} ${ + object.item.ownr_co_nm || "" + } ${ + object.item.v_model_yr ? `- ${object.item.v_model_yr}` : "" + } ${ + object.item.v_make_desc ? `- ${object.item.v_make_desc}` : "" + } ${ + object.item.v_model_desc + ? `- ${object.item.v_model_desc}` + : "" + }`} + key={object.item.id} + /> + )} + /> + + + + + ); +} + +export default connect(null, null)(JobSearchAndSelectModal); From 040dad2ee9de64797adc4f25598b26eea2b8bb10 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Tue, 18 Jul 2023 11:10:03 -0400 Subject: [PATCH 096/105] init of redo of SearchJobModal NotFlashing --- components/Modals/JobIdSearchAndList.jsx | 162 +++++++++++++++++++++++ components/Modals/JobSearchModal.jsx | 53 ++++++++ 2 files changed, 215 insertions(+) create mode 100644 components/Modals/JobIdSearchAndList.jsx create mode 100644 components/Modals/JobSearchModal.jsx diff --git a/components/Modals/JobIdSearchAndList.jsx b/components/Modals/JobIdSearchAndList.jsx new file mode 100644 index 0000000..b47a194 --- /dev/null +++ b/components/Modals/JobIdSearchAndList.jsx @@ -0,0 +1,162 @@ +import { FlatList, RefreshControl, StyleSheet, Text, View } from "react-native"; +import React from "react"; +import { Ionicons } from "@expo/vector-icons"; +import { Button, List, Searchbar } from "react-native-paper"; +import { useState } from "react"; +import { SEARCH_JOBS_FOR_AUTOCOMPLETE } from "../../graphql/jobs.queries"; +import { useQuery } from "@apollo/client"; + +function JobIdSearchAndList({ onClose }) { + const jobSrchNotExported = true; + const jobSrchNotInvoiced = false; + const jobSrchConvertedOnly = false; + + const jobSrchCurrentValue = { id: "temp", ro_number: "Temporary Storage" }; + const jobSrchOnSetCurrentValue = (e) => { + console.info("onSetCurrentValue was called", e); + }; + const jobSrchCurrentValueId = "temp"; + const jobSrchOnSetCurrentValueId = () => { + console.info("onSetCurrentValueId was called"); + }; + + const [searchText, setSearchText] = useState(null); + const [loading2, setLoading2] = useState(null); + + console.log("onClose :", onClose); + // const showModal = () => setVisible(true); + const close = onClose ? onClose : () => console.info("todo add close"); //setVisible(false); + const onChangeSearch = (query) => { + console.log("onChangeSearch text:", query); + setSearchText(query); + }; + const onRefresh = async () => { + //7/18 + setLoading2(true); + // refetch(); + setTimeout(() => { + setLoading2(false); + }, 1000); + + //7/17 + // setRefreshing(true); + // console.log(" "); + // console.log(" "); + // console.log(" "); + // console.log(" "); + // console.log(" "); + // console.log("onRefresh was called"); + + // console.log("data:", data); + // refetch({ + // notInvoiced: jobSrchNotInvoiced, + // notExported: jobSrchNotExported, + // isConverted: jobSrchConvertedOnly, + // search: searchText, + // }); + }; + + const { loading, error, data, refetch } = useQuery( + SEARCH_JOBS_FOR_AUTOCOMPLETE, + { + // fetchPolicy: "cache-and-network", + variables: { + search: searchText, + ...(jobSrchConvertedOnly || jobSrchNotExported + ? { + ...(jobSrchConvertedOnly ? { isConverted: true } : {}), + ...(jobSrchNotExported ? { notExported: true } : {}), + ...(jobSrchNotInvoiced ? { notInvoiced: true } : {}), + } + : {}), + }, + skip: !!!searchText, + fetchPolicy: "network-only", + nextFetchPolicy: "network-only", + } + ); + + return ( + + + + onChangeSearch(text)} + value={searchText} + /> + + + } + // data={[{ id: "temp", ro_number: "Temporary Storage" }, ...jobs]} + data={data?.search_jobs} + keyExtractor={(item) => item.id} + renderItem={(object) => ( + { + // jobSrchOnSetCurrentValue(object.item); + // jobSrchOnSetCurrentValueId(object.item.id); + hideModal(); + setSearchText(""); + }} + left={() => { + if (object.item.id !== jobSrchCurrentValueId) return null; + return ( + + ); + }} + titleStyle={{ + ...(object.item.id === jobSrchCurrentValueId + ? { color: "dodgerblue" } + : {}), + }} + title={`${ + object.item.ro_number ? `${object.item.ro_number} ` : `` + }${object.item.ownr_fn || ""} ${object.item.ownr_ln || ""}${ + object.item.v_model_yr ? `- ${object.item.v_model_yr}` : "" + }${object.item.v_make_desc ? `- ${object.item.v_make_desc}` : ""}${ + object.item.v_model_desc ? `- ${object.item.v_model_desc}` : "" + }`} + key={object.item.id} + /> + )} + ListEmptyComponent={ + + No Data + + } + /> + + ); +} + +export default JobIdSearchAndList; + +const styles = StyleSheet.create({}); diff --git a/components/Modals/JobSearchModal.jsx b/components/Modals/JobSearchModal.jsx new file mode 100644 index 0000000..cd10321 --- /dev/null +++ b/components/Modals/JobSearchModal.jsx @@ -0,0 +1,53 @@ +import { StyleSheet, Text, View } from "react-native"; +import React from "react"; +import { useTranslation } from "react-i18next"; +import { Button, Modal, Portal } from "react-native-paper"; +import JobIdSearchAndList from "./JobIdSearchAndList"; +import { useState } from "react"; + +function JobSearchModal() { + const { t } = useTranslation(); + const [visible, setVisible] = useState(false); + const showModal = () => setVisible(true); + const hideModal = () => setVisible(false); + return ( + + + + + + + + + ); +} + +export default JobSearchModal; + +const styles = StyleSheet.create({}); From 9675147845cb7cdd82f5ac28b25e7ab55f0ae3c9 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Wed, 19 Jul 2023 17:13:44 -0400 Subject: [PATCH 097/105] working on adding debounce --- components/Modals/JobSearchAndSelectModal.jsx | 246 ++++++++++++------ 1 file changed, 160 insertions(+), 86 deletions(-) diff --git a/components/Modals/JobSearchAndSelectModal.jsx b/components/Modals/JobSearchAndSelectModal.jsx index 24fafd1..6afdeab 100644 --- a/components/Modals/JobSearchAndSelectModal.jsx +++ b/components/Modals/JobSearchAndSelectModal.jsx @@ -1,38 +1,20 @@ -import { useQuery } from "@apollo/client"; +import { useLazyQuery, useQuery } from "@apollo/client"; import { Ionicons } from "@expo/vector-icons"; import React from "react"; import { useTranslation } from "react-i18next"; -import { FlatList, RefreshControl, View } from "react-native"; +import { FlatList, RefreshControl, Text, View } from "react-native"; import { Button, List, Modal, Portal, Searchbar } from "react-native-paper"; import { connect } from "react-redux"; // import { createStructuredSelector } from "reselect"; -import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries"; -// import { setCameraJob, setCameraJobId } from "../../redux/app/app.actions"; -// import { -// selectCurrentCameraJob, -// selectCurrentCameraJobId, -// } from "../../redux/app/app.selectors"; -// import { selectBodyshop } from "../../redux/user/user.selectors"; +import { + SEARCH_JOBS_FOR_AUTOCOMPLETE, +} from "../../graphql/jobs.queries"; import ErrorDisplay from "../error-display/error-display.component"; -import LoadingDisplay from "../loading-display/loading-display.component"; +// import LoadingDisplay from "../loading-display/loading-display.component"; +import _ from 'lodash'; -// const mapStateToProps = createStructuredSelector({ -// cameraJobId: selectCurrentCameraJobId, -// cameraJob: selectCurrentCameraJob, -// }); -// const mapDispatchToProps = (dispatch) => ({ -// setCameraJobId: (id) => dispatch(setCameraJobId(id)), -// setCameraJob: (job) => dispatch(setCameraJob(job)), -// }); - -export function JobSearchAndSelectModal( - props, -// cameraJobId, -// setCameraJobId, -// cameraJob, -// setCameraJob, -) { +export function JobSearchAndSelectModal(props) { const jobSrchNotExported = props?.notExported !== undefined ? props.notExported : true; const jobSrchNotInvoiced = @@ -40,82 +22,157 @@ export function JobSearchAndSelectModal( const jobSrchConvertedOnly = props?.convertedOnly !== undefined ? props.convertedOnly : false; - const jobSrchCurrentValue = props?.currentValue !== undefined ? props.currentValue : { id: "temp", ro_number: "Temporary Storage" }; - const jobSrchOnSetCurrentValue = props?.onSetCurrentValue !== undefined ? props.onSetCurrentValue : (e) => { console.info("onSetCurrentValue was called",e);}; - const jobSrchCurrentValueId = props?.currentValueId !== undefined ? props.currentValueId : "temp"; - const jobSrchOnSetCurrentValueId = props?.onSetCurrentValueId !== undefined ? props.onSetCurrentValueId : () => { console.info("onSetCurrentValueId was called"); }; - + const jobSrchCurrentValue = + props?.currentValue !== undefined + ? props.currentValue + : { id: "temp", ro_number: "Temporary Storage" }; + const jobSrchOnSetCurrentValue = + props?.onSetCurrentValue !== undefined + ? props.onSetCurrentValue + : (e) => { + console.info("onSetCurrentValue was called", e); + }; + const jobSrchCurrentValueId = + props?.currentValueId !== undefined ? props.currentValueId : "temp"; + const jobSrchOnSetCurrentValueId = + props?.onSetCurrentValueId !== undefined + ? props.onSetCurrentValueId + : () => { + console.info("onSetCurrentValueId was called"); + }; + console.log(" "); console.log("*****JobSearchAndSelectModal*****"); - console.log("props:", props);//works -// console.log("notExported:", jobSrchNotExported);//works -// console.log("notInvoiced:", jobSrchNotInvoiced);//works -// console.log("convertedOnly:", jobSrchConvertedOnly);//works - console.log("jobSrchCurrentValue:", jobSrchCurrentValue); //{"id": "temp", "ro_number": "Temporary Storage"} - console.log("jobSrchOnSetCurrentValue:", jobSrchOnSetCurrentValue); - console.log("jobSrchCurrentValueId:", jobSrchCurrentValueId); //temp will be currentValue - console.log("jobSrchOnSetCurrentValueId:", jobSrchOnSetCurrentValueId); // will be onSetCurrentValue - + // console.log("props:", props);//works + // console.log("notExported:", jobSrchNotExported);//works + // console.log("notInvoiced:", jobSrchNotInvoiced);//works + // console.log("convertedOnly:", jobSrchConvertedOnly);//works + // console.log("jobSrchCurrentValue:", jobSrchCurrentValue); //{"id": "temp", "ro_number": "Temporary Storage"} + // console.log("jobSrchOnSetCurrentValue:", jobSrchOnSetCurrentValue); + // console.log("jobSrchCurrentValueId:", jobSrchCurrentValueId); //temp will be currentValue + // console.log("jobSrchOnSetCurrentValueId:", jobSrchOnSetCurrentValueId); // will be onSetCurrentValue - const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, { - fetchPolicy: "cache-and-network", - variables: { - statuses: false || ["Open", "Open*"], - }, - }); const { t } = useTranslation(); const [visible, setVisible] = React.useState(false); - const [searchQuery, setSearchQuery] = React.useState(""); - if (loading) return ; + const [searchText, setSearchText] = React.useState(null); + + //TODO:Replace QUERY_ALL_ACTIVE_JOBS with SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE and update variables, statuses: false || ["Open", "Open*"], + // with search: value, + // ...(convertedOnly || notExported + // ? { + // ...(convertedOnly ? { isConverted: true } : {}), + // ...(notExported ? { notExported: true } : {}), + // ...(notInvoiced ? { notInvoiced: true } : {}), + // } + // : {}), + + // const { loading, error, data, refetch } = useQuery( + // SEARCH_JOBS_FOR_AUTOCOMPLETE, + // { + // fetchPolicy: "cache-and-network", + // variables: { + // search: searchText, + // ...(jobSrchConvertedOnly || jobSrchNotExported + // ? { + // ...(jobSrchConvertedOnly ? { isConverted: true } : {}), + // ...(jobSrchNotExported ? { notExported: true } : {}), + // ...(jobSrchNotInvoiced ? { notInvoiced: true } : {}), + // } + // : {}), + // }, + // } + // ); + // const searchQuery = useQuery([SEARCH_JOBS_FOR_AUTOCOMPLETE, debouncedSearchTerm], () => fetchSearchResults(debouncedSearchTerm)); + const [searchQuery, { loading, error, data }] = useLazyQuery( + SEARCH_JOBS_FOR_AUTOCOMPLETE, + { + // fetchPolicy: "cache-and-network", + // variables: { + // search: searchText, + // ...(jobSrchConvertedOnly || jobSrchNotExported + // ? { + // ...(jobSrchConvertedOnly ? { isConverted: true } : {}), + // ...(jobSrchNotExported ? { notExported: true } : {}), + // ...(jobSrchNotInvoiced ? { notInvoiced: true } : {}), + // } + // : {}), + // }, + } + ); if (error) return ; const showModal = () => setVisible(true); const hideModal = () => setVisible(false); - const onRefresh = async () => { - console.log("onRefresh was called"); - return refetch(); + // refetch({ + // notInvoiced: jobSrchNotInvoiced, + // notExported: jobSrchNotExported, + // isConverted: jobSrchConvertedOnly, + // search: searchText, + // }); }; + const executeSearch = (v) => { + console.log("executeSearchWithV:", v); + if (v && v !== "") searchQuery(v); + }; + const debouncedExecuteSearch = _.debounce(executeSearch, 1000); - const onChangeSearch = (query) => setSearchQuery(query); + const onChangeSearch = (query) => { + setSearchText(query); + debouncedExecuteSearch({variables: { + search: query, + ...(jobSrchConvertedOnly || jobSrchNotExported + ? { + ...(jobSrchConvertedOnly ? { isConverted: true } : {}), + ...(jobSrchNotExported ? { notExported: true } : {}), + ...(jobSrchNotInvoiced ? { notInvoiced: true } : {}), + } + : {}), + }}); + // debouncedSearchTerm(query); + + }; + // const debouncedSearchTerm = debounce(searchText => { + // // Fetch search results using useQuery + // searchQuery.refetch(); + // }, 1000); + + //TODO:Replace this with returns of the other call jobs:search_jobs, This should be done const jobs = data - ? searchQuery === "" - ? data.jobs - : data.jobs.filter( + ? searchText === "" + ? data.search_jobs + : data.search_jobs.filter( (j) => (j.ro_number || "") .toString() .toLowerCase() - .includes(searchQuery.toLowerCase()) || - (j.ownr_co_nm || "") - .toLowerCase() - .includes(searchQuery.toLowerCase()) || + .includes(searchText.toLowerCase()) || (j.ownr_fn || "") .toLowerCase() - .includes(searchQuery.toLowerCase()) || + .includes(searchText.toLowerCase()) || (j.ownr_ln || "") .toLowerCase() - .includes(searchQuery.toLowerCase()) || - (j.plate_no || "") - .toLowerCase() - .includes(searchQuery.toLowerCase()) || + .includes(searchText.toLowerCase()) || (j.v_model_desc || "") .toLowerCase() - .includes(searchQuery.toLowerCase()) || + .includes(searchText.toLowerCase()) || (j.v_make_desc || "") .toLowerCase() - .includes(searchQuery.toLowerCase()) + .includes(searchText.toLowerCase()) ) : []; + //TODO:Replace the Button with returns of the other call, This should be done + //Side Note removed ${jobSrchCurrentValue.ownr_co_nm || ""} from button display when jobSrchCurrentValueId has a value + //Side Note removed ${object.item.ownr_co_nm || ""} from title of } - data={[{ id: "temp", ro_number: "Temporary Storage" }, ...jobs]} + data={data?.search_jobs} keyExtractor={(item) => item.id} renderItem={(object) => ( { - //setCameraJob(object.item); - //setCameraJobId(object.item.id); jobSrchOnSetCurrentValue(object.item); jobSrchOnSetCurrentValueId(object.item.id); hideModal(); - setSearchQuery(""); + setSearchText(""); }} left={() => { if (object.item.id !== jobSrchCurrentValueId) return null; @@ -175,32 +230,51 @@ export function JobSearchAndSelectModal( }} title={`${ object.item.ro_number ? `${object.item.ro_number} ` : `` - }${object.item.ownr_fn || ""} ${object.item.ownr_ln || ""} ${ - object.item.ownr_co_nm || "" - } ${ + }${object.item.ownr_fn || ""} ${object.item.ownr_ln || ""}${ object.item.v_model_yr ? `- ${object.item.v_model_yr}` : "" - } ${ + }${ object.item.v_make_desc ? `- ${object.item.v_make_desc}` : "" - } ${ - object.item.v_model_desc - ? `- ${object.item.v_model_desc}` - : "" + }${ + object.item.v_model_desc ? `- ${object.item.v_model_desc}` : "" }`} key={object.item.id} /> )} + ListEmptyComponent={ + + No Data + + } /> - From eb75909106e7da3f01e7f8df7611427281246f6d Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 20 Jul 2023 12:28:05 -0400 Subject: [PATCH 098/105] ModalForJobBeforeCleanup --- components/Modals/JobSearchAndSelectModal.jsx | 150 ++++++++++-------- 1 file changed, 85 insertions(+), 65 deletions(-) diff --git a/components/Modals/JobSearchAndSelectModal.jsx b/components/Modals/JobSearchAndSelectModal.jsx index 6afdeab..92989a7 100644 --- a/components/Modals/JobSearchAndSelectModal.jsx +++ b/components/Modals/JobSearchAndSelectModal.jsx @@ -6,13 +6,11 @@ import { FlatList, RefreshControl, Text, View } from "react-native"; import { Button, List, Modal, Portal, Searchbar } from "react-native-paper"; import { connect } from "react-redux"; // import { createStructuredSelector } from "reselect"; -import { - SEARCH_JOBS_FOR_AUTOCOMPLETE, -} from "../../graphql/jobs.queries"; +import { SEARCH_JOBS_FOR_AUTOCOMPLETE } from "../../graphql/jobs.queries"; import ErrorDisplay from "../error-display/error-display.component"; // import LoadingDisplay from "../loading-display/loading-display.component"; -import _ from 'lodash'; - +import _ from "lodash"; +import { useCallback } from "react"; export function JobSearchAndSelectModal(props) { const jobSrchNotExported = @@ -25,36 +23,40 @@ export function JobSearchAndSelectModal(props) { const jobSrchCurrentValue = props?.currentValue !== undefined ? props.currentValue - : { id: "temp", ro_number: "Temporary Storage" }; + : { id: "temp", ro_number: "No Selection" }; const jobSrchOnSetCurrentValue = props?.onSetCurrentValue !== undefined ? props.onSetCurrentValue : (e) => { console.info("onSetCurrentValue was called", e); }; - const jobSrchCurrentValueId = - props?.currentValueId !== undefined ? props.currentValueId : "temp"; - const jobSrchOnSetCurrentValueId = - props?.onSetCurrentValueId !== undefined - ? props.onSetCurrentValueId - : () => { - console.info("onSetCurrentValueId was called"); - }; + // const jobSrchCurrentValueId = + // props?.currentValueId !== undefined ? props.currentValueId : "temp"; + // const jobSrchOnSetCurrentValueId = + // props?.onSetCurrentValueId !== undefined + // ? props.onSetCurrentValueId + // : () => { + // console.info("onSetCurrentValueId was called"); + // }; console.log(" "); console.log("*****JobSearchAndSelectModal*****"); - // console.log("props:", props);//works - // console.log("notExported:", jobSrchNotExported);//works - // console.log("notInvoiced:", jobSrchNotInvoiced);//works - // console.log("convertedOnly:", jobSrchConvertedOnly);//works - // console.log("jobSrchCurrentValue:", jobSrchCurrentValue); //{"id": "temp", "ro_number": "Temporary Storage"} - // console.log("jobSrchOnSetCurrentValue:", jobSrchOnSetCurrentValue); - // console.log("jobSrchCurrentValueId:", jobSrchCurrentValueId); //temp will be currentValue - // console.log("jobSrchOnSetCurrentValueId:", jobSrchOnSetCurrentValueId); // will be onSetCurrentValue + // console.log("props:", props);//works + // console.log("notExported:", jobSrchNotExported);//works + // console.log("notInvoiced:", jobSrchNotInvoiced);//works + // console.log("convertedOnly:", jobSrchConvertedOnly);//works + // console.log("jobSrchCurrentValue:", jobSrchCurrentValue); //{"id": "temp", "ro_number": "Temporary Storage"} + // console.log("jobSrchOnSetCurrentValue:", jobSrchOnSetCurrentValue); + // console.log("jobSrchCurrentValueId:", jobSrchCurrentValueId); //temp will be currentValue + // console.log("jobSrchOnSetCurrentValueId:", jobSrchOnSetCurrentValueId); // will be onSetCurrentValue const { t } = useTranslation(); const [visible, setVisible] = React.useState(false); - const [searchText, setSearchText] = React.useState(null); + const [searchText, setSearchText] = React.useState(""); + + // const [error, setError] = React.useState(null); + // const [data, setData] = React.useState(null); + // const [loading, setLoading] = React.useState(null); //TODO:Replace QUERY_ALL_ACTIVE_JOBS with SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE and update variables, statuses: false || ["Open", "Open*"], // with search: value, @@ -66,6 +68,7 @@ export function JobSearchAndSelectModal(props) { // } // : {}), + //orig works 7/20 // const { loading, error, data, refetch } = useQuery( // SEARCH_JOBS_FOR_AUTOCOMPLETE, // { @@ -82,11 +85,13 @@ export function JobSearchAndSelectModal(props) { // }, // } // ); + //temp placeholder commented code // const searchQuery = useQuery([SEARCH_JOBS_FOR_AUTOCOMPLETE, debouncedSearchTerm], () => fetchSearchResults(debouncedSearchTerm)); - const [searchQuery, { loading, error, data }] = useLazyQuery( + //2nd try with uselazyquery + const [searchQuery, { loading, error, data, refetch }] = useLazyQuery( SEARCH_JOBS_FOR_AUTOCOMPLETE, { - // fetchPolicy: "cache-and-network", + fetchPolicy: "cache-and-network", // variables: { // search: searchText, // ...(jobSrchConvertedOnly || jobSrchNotExported @@ -99,27 +104,45 @@ export function JobSearchAndSelectModal(props) { // }, } ); + if (error) return ; const showModal = () => setVisible(true); const hideModal = () => setVisible(false); const onRefresh = async () => { - // refetch({ - // notInvoiced: jobSrchNotInvoiced, - // notExported: jobSrchNotExported, - // isConverted: jobSrchConvertedOnly, - // search: searchText, + // searchDebouncer({ + // variables: { + // search: searchText, + // ...(jobSrchConvertedOnly || jobSrchNotExported + // ? { + // ...(jobSrchConvertedOnly ? { isConverted: true } : {}), + // ...(jobSrchNotExported ? { notExported: true } : {}), + // ...(jobSrchNotInvoiced ? { notInvoiced: true } : {}), + // } + // : {}), + // }, // }); + refetch({ + notInvoiced: jobSrchNotInvoiced, + notExported: jobSrchNotExported, + isConverted: jobSrchConvertedOnly, + search: searchText, + }); }; - const executeSearch = (v) => { - console.log("executeSearchWithV:", v); + + const search = (v) => { + console.log("execute search with :", v); if (v && v !== "") searchQuery(v); }; - const debouncedExecuteSearch = _.debounce(executeSearch, 1000); + const searchDebouncer = useCallback( + _.debounce(search, 1000), + [] + ); - const onChangeSearch = (query) => { - setSearchText(query); - debouncedExecuteSearch({variables: { + const onChangeSearch = (query) => { + setSearchText(query); + searchDebouncer({ + variables: { search: query, ...(jobSrchConvertedOnly || jobSrchNotExported ? { @@ -128,17 +151,10 @@ export function JobSearchAndSelectModal(props) { ...(jobSrchNotInvoiced ? { notInvoiced: true } : {}), } : {}), - }}); - // debouncedSearchTerm(query); - - }; + }, + }); + }; - // const debouncedSearchTerm = debounce(searchText => { - // // Fetch search results using useQuery - // searchQuery.refetch(); - // }, 1000); - - //TODO:Replace this with returns of the other call jobs:search_jobs, This should be done const jobs = data ? searchText === "" ? data.search_jobs @@ -147,7 +163,7 @@ export function JobSearchAndSelectModal(props) { (j.ro_number || "") .toString() .toLowerCase() - .includes(searchText.toLowerCase()) || + .includes(searchText.toLowerCase()) || (j.ownr_fn || "") .toLowerCase() .includes(searchText.toLowerCase()) || @@ -162,11 +178,7 @@ export function JobSearchAndSelectModal(props) { .includes(searchText.toLowerCase()) ) : []; - //TODO:Replace the Button with returns of the other call, This should be done - //Side Note removed ${jobSrchCurrentValue.ownr_co_nm || ""} from button display when jobSrchCurrentValueId has a value - //Side Note removed ${object.item.ownr_co_nm || ""} from title of @@ -208,12 +220,12 @@ export function JobSearchAndSelectModal(props) { { jobSrchOnSetCurrentValue(object.item); - jobSrchOnSetCurrentValueId(object.item.id); + // jobSrchOnSetCurrentValueId(object.item.id); hideModal(); setSearchText(""); }} left={() => { - if (object.item.id !== jobSrchCurrentValueId) return null; + if (object.item.id !== jobSrchCurrentValue?.id) return null; return ( @@ -255,16 +269,22 @@ export function JobSearchAndSelectModal(props) { /> - + // - // } + // + // + // )} /> - } refreshControl={ - + + } + ListEmptyComponent={ + + No Data + } /> @@ -283,7 +303,7 @@ const MyItem = ({ itemState, style }) => { {!!items ? ( items.map((item) => ) - ) : !!itemState.content ? ( + ) : !!itemState?.content ? ( itemState.content ) : ( No Data @@ -301,6 +321,12 @@ const localStyles = StyleSheet.create({ localCardStyle: { margin: 4, }, + containerNoData: { + flex: 1, + padding: 10, + alignItems: "center", + justifyContent: "center", + }, }); export default connect( From 69eaf5eba6f976b46dd3f751e6505fac436f27de Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Thu, 20 Jul 2023 17:00:27 -0400 Subject: [PATCH 100/105] updated timeticketcreate --- .../screen-time-ticket-create.component.jsx | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index 6ba5462..f30f46a 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -32,6 +32,7 @@ import { useNavigation } from "@react-navigation/native"; import styles from "../styles"; import StyleRepeater from "../style-repeater/style-repeater"; import { FlatList } from "react-native"; +import JobSearchAndSelectModal from "../Modals/JobSearchAndSelectModal"; const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, @@ -60,9 +61,7 @@ export function TimeTicketCreate({ const [date2, setDate2] = useState(new Date()); const [currentSCC, setCurrentSCC] = useState(null); - // const [currentSJob, setCurrentSJob] = useState(null); - const [currentSJobId, setCurrentSJobId] = useState(null); - + const [curSelClockIntoJob,setCurSelClockIntoJob] = useState(null); const showDatePicker = () => { setDatePickerVisibility(true); }; @@ -88,7 +87,7 @@ export function TimeTicketCreate({ if ( !!currentSCC?.value && - !!currentSJobId?.value && + !!curSelClockIntoJob?.id && !!values.productivehours && !!currentBodyshop.id && !!currentEmployee?.technician?.id && @@ -120,10 +119,7 @@ export function TimeTicketCreate({ return; } } - - // if (date2) console.log("rate :", currentRatesNCostCenters && currentSCC?.value ? currentRatesNCostCenters.filter((r) => r.cost_center === currentSCC?.value)[0].rate : null);//2023-05-16T16:45:27.154Z - // if (date2) console.log("bodyshopid : ", currentBodyshop.id); - // if (date2) console.log("moment(date2).format(YYYY-MM-DD)", moment(date2).format("YYYY-MM-DD")); + const tempVariablesObj = { variables: { timeTicketInput: [ @@ -149,7 +145,7 @@ export function TimeTicketCreate({ currentEmployee && currentEmployee.technician && currentEmployee.technician?.flat_rate, - jobid: currentSJobId?.value, + jobid: curSelClockIntoJob?.id, productivehrs: values?.productivehours, rate: currentRatesNCostCenters && currentSCC?.value @@ -182,18 +178,8 @@ export function TimeTicketCreate({ // console.log("insertTicket, result. :", result.data); navigation.goBack(); } - // if (completedCallback) completedCallback(); }; - // const handleMutationError = (error) => { - // // setEnterAgain(false); - // console.log("insertTicket, result.error :", error); - // setError( - // error?.message ? JSON.stringify(error?.message) : JSON.stringify(error) - // ); - // setLoading(false); - // }; - const onRefresh = useCallback(() => { setLoading(true); // refetch(); @@ -210,7 +196,6 @@ export function TimeTicketCreate({ {({ handleChange, handleBlur, handleSubmit, values }) => ( - + /> */} + ); diff --git a/translations/en-US/common.json b/translations/en-US/common.json index 1ca773b..9e6f473 100644 --- a/translations/en-US/common.json +++ b/translations/en-US/common.json @@ -369,7 +369,7 @@ "missingvalues": "Please make sure all fields have a value." }, "titles": { - "createtimeticket": "Create a Time Ticket" + "createtimeticket": "New Time Ticket" } }, "joblines": { From d29a8a6d66ec05955b781cf8c80ea9764a5abc16 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Tue, 25 Jul 2023 14:10:27 -0400 Subject: [PATCH 102/105] update laboralloctable --- .../labor-allocations-table.component.jsx | 37 +++++-------------- translations/en-US/common.json | 11 ++++++ translations/es-MX/common.json | 11 ++++++ translations/fr-CA/common.json | 11 ++++++ 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/components/labor-allocations-table/labor-allocations-table.component.jsx b/components/labor-allocations-table/labor-allocations-table.component.jsx index e9ab057..08bca5b 100644 --- a/components/labor-allocations-table/labor-allocations-table.component.jsx +++ b/components/labor-allocations-table/labor-allocations-table.component.jsx @@ -1,6 +1,6 @@ -import React, { useEffect, useMemo, useState } from "react"; +import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import { FlatList, RefreshControl, StyleSheet, Text, View } from "react-native"; +import { FlatList, StyleSheet, Text, View } from "react-native"; import _ from "lodash"; import { ActivityIndicator, Card, DataTable, Divider } from "react-native-paper"; import { GET_LINE_TICKET_BY_PK } from "../../graphql/jobs.queries"; @@ -18,34 +18,19 @@ const mapStateToProps = createStructuredSelector({ }); export function LaborAllocationsTable({ jobId, bodyshop, technician,costCenterDiff,selectedCostCenter, style, shouldRefresh}) { - // console.log("LaborAllocationsTable, costCenterDiff", costCenterDiff); - // console.log("LaborAllocationsTable, selectedCostCenter", selectedCostCenter); const { t } = useTranslation(); - - const onRefresh = async () => { - // console.log("LaborAllocationsTable refetch"); - return refetch(); - }; - + const onRefresh = async () => { return refetch(); }; const { loading, error, data, refetch } = useQuery(GET_LINE_TICKET_BY_PK, { variables: { id: jobId }, skip: !!!jobId, fetchPolicy: "network-only", nextFetchPolicy: "network-only", }); - - // console.log("LaborAllocationsTable, data", data); if (error) return ; - // if (loading) return ; const [totals, setTotals] = useState([]); - // useEffect(() => { - // // console.log("LaborAllocationsTable useEffect on data change"); - // }, [data]); - useEffect(() => { - // console.log("LaborAllocationsTable useEffect on [all inputs] change",data?.joblines,data?.adjustments); if (!!data?.joblines && !!data?.timetickets && !!bodyshop){ let temptotals = CalculateAllocationsTotals( bodyshop, @@ -70,7 +55,6 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician,costCenterDi }, [data?.joblines, data?.timetickets, bodyshop, data?.adjustments, jobId, selectedCostCenter]); useEffect(() => { - // console.log("made it here, shouldRefresh is :", shouldRefresh ); !!shouldRefresh && shouldRefresh ? onRefresh() : null },[shouldRefresh]); @@ -86,22 +70,21 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician,costCenterDi }, { hrs_total: 0, hrs_claimed: 0, adjustments: 0, difference: 0 } ); - // console.log("labor summary is:", summary); if (loading) return ; return ( {typeof data !== "undefined" ? ( - + - Cost Center - Hours Total - Hours Claimed + {t("laborallocations.labels.costcenter")} + {t("laborallocations.labels.hourstotal")} + {t("laborallocations.labels.hoursclaimed")} {/* Hours Claimed */} - Adjustments - Difference + {t("laborallocations.labels.adjustments")} + {t("laborallocations.labels.difference")} @@ -148,7 +131,7 @@ export function LaborAllocationsTable({ jobId, bodyshop, technician,costCenterDi /> {summary && ( - Totals + {t("laborallocations.labels.totals")} {summary.hrs_total.toFixed(1)} diff --git a/translations/en-US/common.json b/translations/en-US/common.json index 9e6f473..cefc4e2 100644 --- a/translations/en-US/common.json +++ b/translations/en-US/common.json @@ -508,6 +508,17 @@ "actions": { "clockout": "Clock Out" } + }, + "laborallocations": { + "labels": { + "laborallocations": "Labor Allocations", + "costcenter": "Cost Center", + "hourstotal": "Hours Total", + "hoursclaimed": "Hours Claimed", + "adjustments": "Adjustments", + "difference": "Difference", + "totals": "Totals" + } } } } diff --git a/translations/es-MX/common.json b/translations/es-MX/common.json index 145017f..3d8180b 100644 --- a/translations/es-MX/common.json +++ b/translations/es-MX/common.json @@ -508,6 +508,17 @@ "actions": { "clockout": "" } + }, + "laborallocations": { + "labels": { + "laborallocations": "", + "costcenter": "", + "hourstotal": "", + "hoursclaimed": "", + "adjustments": "", + "difference": "", + "totals": "" + } } } } diff --git a/translations/fr-CA/common.json b/translations/fr-CA/common.json index c52eb80..e8f1ddc 100644 --- a/translations/fr-CA/common.json +++ b/translations/fr-CA/common.json @@ -508,6 +508,17 @@ "actions": { "clockout": "" } + }, + "laborallocations": { + "labels": { + "laborallocations": "", + "costcenter": "", + "hourstotal": "", + "hoursclaimed": "", + "adjustments": "", + "difference": "", + "totals": "" + } } } } From 1bc46e87bfc23538e820aec950287f624e7a7a5f Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Tue, 25 Jul 2023 23:27:10 -0400 Subject: [PATCH 103/105] update files --- .../create-time-ticket-button.component.jsx | 6 - components/Modals/JobIdSearchAndList.jsx | 162 ------------------ components/Modals/JobSearchAndSelectModal.jsx | 12 +- components/Modals/JobSearchModal.jsx | 53 ------ components/Selects/select-cost-center.jsx | 13 +- .../keyboards/KeyboardAvoidingComponent.js | 6 +- .../screen-main/screen-main.component.jsx | 9 +- .../screen-time-ticket-browser.component.jsx | 14 +- .../sign-out-button.component.jsx | 2 - .../clockedin-list-item.component.jsx | 5 - .../screen-time-ticket-clockoff.component.jsx | 36 +--- .../screen-time-ticket-create.component.jsx | 54 ++---- translations/en-US/common.json | 7 +- translations/es-MX/common.json | 7 +- translations/fr-CA/common.json | 7 +- 15 files changed, 40 insertions(+), 353 deletions(-) delete mode 100644 components/Modals/JobIdSearchAndList.jsx delete mode 100644 components/Modals/JobSearchModal.jsx diff --git a/components/Buttons/create-time-ticket-button.component.jsx b/components/Buttons/create-time-ticket-button.component.jsx index 9735dc3..2c5da22 100644 --- a/components/Buttons/create-time-ticket-button.component.jsx +++ b/components/Buttons/create-time-ticket-button.component.jsx @@ -5,12 +5,6 @@ import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { useNavigation } from "@react-navigation/native"; - - -// const mapDispatchToProps = (dispatch) => ({ -// signOut: () => dispatch(employeeSignOut()), -// }); - export function AddTimeTicketButton() { const navigation = useNavigation(); diff --git a/components/Modals/JobIdSearchAndList.jsx b/components/Modals/JobIdSearchAndList.jsx deleted file mode 100644 index b47a194..0000000 --- a/components/Modals/JobIdSearchAndList.jsx +++ /dev/null @@ -1,162 +0,0 @@ -import { FlatList, RefreshControl, StyleSheet, Text, View } from "react-native"; -import React from "react"; -import { Ionicons } from "@expo/vector-icons"; -import { Button, List, Searchbar } from "react-native-paper"; -import { useState } from "react"; -import { SEARCH_JOBS_FOR_AUTOCOMPLETE } from "../../graphql/jobs.queries"; -import { useQuery } from "@apollo/client"; - -function JobIdSearchAndList({ onClose }) { - const jobSrchNotExported = true; - const jobSrchNotInvoiced = false; - const jobSrchConvertedOnly = false; - - const jobSrchCurrentValue = { id: "temp", ro_number: "Temporary Storage" }; - const jobSrchOnSetCurrentValue = (e) => { - console.info("onSetCurrentValue was called", e); - }; - const jobSrchCurrentValueId = "temp"; - const jobSrchOnSetCurrentValueId = () => { - console.info("onSetCurrentValueId was called"); - }; - - const [searchText, setSearchText] = useState(null); - const [loading2, setLoading2] = useState(null); - - console.log("onClose :", onClose); - // const showModal = () => setVisible(true); - const close = onClose ? onClose : () => console.info("todo add close"); //setVisible(false); - const onChangeSearch = (query) => { - console.log("onChangeSearch text:", query); - setSearchText(query); - }; - const onRefresh = async () => { - //7/18 - setLoading2(true); - // refetch(); - setTimeout(() => { - setLoading2(false); - }, 1000); - - //7/17 - // setRefreshing(true); - // console.log(" "); - // console.log(" "); - // console.log(" "); - // console.log(" "); - // console.log(" "); - // console.log("onRefresh was called"); - - // console.log("data:", data); - // refetch({ - // notInvoiced: jobSrchNotInvoiced, - // notExported: jobSrchNotExported, - // isConverted: jobSrchConvertedOnly, - // search: searchText, - // }); - }; - - const { loading, error, data, refetch } = useQuery( - SEARCH_JOBS_FOR_AUTOCOMPLETE, - { - // fetchPolicy: "cache-and-network", - variables: { - search: searchText, - ...(jobSrchConvertedOnly || jobSrchNotExported - ? { - ...(jobSrchConvertedOnly ? { isConverted: true } : {}), - ...(jobSrchNotExported ? { notExported: true } : {}), - ...(jobSrchNotInvoiced ? { notInvoiced: true } : {}), - } - : {}), - }, - skip: !!!searchText, - fetchPolicy: "network-only", - nextFetchPolicy: "network-only", - } - ); - - return ( - - - - onChangeSearch(text)} - value={searchText} - /> - - - } - // data={[{ id: "temp", ro_number: "Temporary Storage" }, ...jobs]} - data={data?.search_jobs} - keyExtractor={(item) => item.id} - renderItem={(object) => ( - { - // jobSrchOnSetCurrentValue(object.item); - // jobSrchOnSetCurrentValueId(object.item.id); - hideModal(); - setSearchText(""); - }} - left={() => { - if (object.item.id !== jobSrchCurrentValueId) return null; - return ( - - ); - }} - titleStyle={{ - ...(object.item.id === jobSrchCurrentValueId - ? { color: "dodgerblue" } - : {}), - }} - title={`${ - object.item.ro_number ? `${object.item.ro_number} ` : `` - }${object.item.ownr_fn || ""} ${object.item.ownr_ln || ""}${ - object.item.v_model_yr ? `- ${object.item.v_model_yr}` : "" - }${object.item.v_make_desc ? `- ${object.item.v_make_desc}` : ""}${ - object.item.v_model_desc ? `- ${object.item.v_model_desc}` : "" - }`} - key={object.item.id} - /> - )} - ListEmptyComponent={ - - No Data - - } - /> - - ); -} - -export default JobIdSearchAndList; - -const styles = StyleSheet.create({}); diff --git a/components/Modals/JobSearchAndSelectModal.jsx b/components/Modals/JobSearchAndSelectModal.jsx index aebedf6..2b55159 100644 --- a/components/Modals/JobSearchAndSelectModal.jsx +++ b/components/Modals/JobSearchAndSelectModal.jsx @@ -8,10 +8,7 @@ import { connect } from "react-redux"; import { SEARCH_JOBS_FOR_AUTOCOMPLETE } from "../../graphql/jobs.queries"; import ErrorDisplay from "../error-display/error-display.component"; import _ from "lodash"; -import { useCallback } from "react"; -import { useRef } from "react"; -import { useEffect } from "react"; - +import { useCallback,useRef, useEffect } from "react"; const useIsMounted = () => { const isMounted = useRef(false); @@ -38,7 +35,7 @@ export function JobSearchAndSelectModal(props) { const jobSrchCurrentValue = props?.currentValue !== undefined ? props.currentValue - : { id: "temp", ro_number: "No Selection" }; + : { id:"temp", ro_number:t("selectjobid.labels.noselection") }; const jobSrchOnSetCurrentValue = props?.onSetCurrentValue !== undefined ? props.onSetCurrentValue @@ -84,7 +81,6 @@ export function JobSearchAndSelectModal(props) { const inputSearch = useRef(null); const isMounted = useIsMounted(); const setFocus = useCallback(() => { - console.log("setFocus called",inputSearch); if (inputSearch.current) { inputSearch.current.focus(); } @@ -183,7 +179,7 @@ export function JobSearchAndSelectModal(props) { justifyContent: "center", }} > - No Data + {t("selectjobid.labels.nodata")} } /> @@ -205,7 +201,7 @@ export function JobSearchAndSelectModal(props) { > {jobSrchCurrentValue?.id ? jobSrchCurrentValue?.id === "temp" - ? t("mediabrowser.labels.temporarystorage") + ? t("selectjobid.labels.noselection") : `${ jobSrchCurrentValue.ro_number ? `${jobSrchCurrentValue.ro_number} - ` diff --git a/components/Modals/JobSearchModal.jsx b/components/Modals/JobSearchModal.jsx deleted file mode 100644 index cd10321..0000000 --- a/components/Modals/JobSearchModal.jsx +++ /dev/null @@ -1,53 +0,0 @@ -import { StyleSheet, Text, View } from "react-native"; -import React from "react"; -import { useTranslation } from "react-i18next"; -import { Button, Modal, Portal } from "react-native-paper"; -import JobIdSearchAndList from "./JobIdSearchAndList"; -import { useState } from "react"; - -function JobSearchModal() { - const { t } = useTranslation(); - const [visible, setVisible] = useState(false); - const showModal = () => setVisible(true); - const hideModal = () => setVisible(false); - return ( - - - - - - - - - ); -} - -export default JobSearchModal; - -const styles = StyleSheet.create({}); diff --git a/components/Selects/select-cost-center.jsx b/components/Selects/select-cost-center.jsx index 7a4bd99..d22e95e 100644 --- a/components/Selects/select-cost-center.jsx +++ b/components/Selects/select-cost-center.jsx @@ -1,28 +1,21 @@ import React, { useState } from "react"; -import { useQuery } from "@apollo/client"; -import { StyleSheet, Text, View } from "react-native"; +import { StyleSheet, View } from "react-native"; import { Dropdown } from "react-native-element-dropdown"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; - import { selectBodyshop } from "../../redux/user/user.selectors"; -import { QUERY_EMPLOYEE_BY_ID } from "../../graphql/employees.queries"; import { useEffect } from "react"; import { t } from "i18next"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop - // timeTicketJobId: selectCurrentTimeTicketJobId, - // timeTicketJob: selectCurrentTimeTicketJob, }); -// const mapDispatchToProps = {}; - export function CostCenterSelect(props) { const currentRatesNCostCenters = props.currentRatesNCostCenters; const bodyshop = props.bodyshop; - const [value, setValue] = useState(null); + // const [value, setValue] = useState(null); const [isFocus, setIsFocus] = useState(false); const [costCenters, setCostCenters] = useState([]); @@ -52,7 +45,6 @@ export function CostCenterSelect(props) { selectedTextStyle={styles.selectedTextStyle} inputSearchStyle={styles.inputSearchStyle} iconStyle={styles.iconStyle} - maxHeight={200} labelField="label" valueField="value" @@ -64,7 +56,6 @@ export function CostCenterSelect(props) { value={props.currentValue?.value} onChange={(item) => { props.onValueSelected(item); - //setValue(item.value); setIsFocus(false); }} /> diff --git a/components/keyboards/KeyboardAvoidingComponent.js b/components/keyboards/KeyboardAvoidingComponent.js index c845f39..d7e1107 100644 --- a/components/keyboards/KeyboardAvoidingComponent.js +++ b/components/keyboards/KeyboardAvoidingComponent.js @@ -2,8 +2,6 @@ import { View, Text, Platform } from "react-native"; import React from "react"; import { KeyboardAvoidingView } from "react-native"; import { StyleSheet } from "react-native"; -import { TouchableWithoutFeedback } from "react-native"; -import { Keyboard } from "react-native"; const KeyboardAvoidingComponent = ({ children }) => { return ( @@ -12,9 +10,7 @@ const KeyboardAvoidingComponent = ({ children }) => { behavior={Platform.OS === "ios" ? "padding":"height" } style={styles.container} > - {/* */} - {children} - {/* */} + {children} ); }; diff --git a/components/screen-main/screen-main.component.jsx b/components/screen-main/screen-main.component.jsx index 541ec2a..c28af6c 100644 --- a/components/screen-main/screen-main.component.jsx +++ b/components/screen-main/screen-main.component.jsx @@ -130,18 +130,11 @@ const TimeTicketBrowserStackNavigator = connect( const appState = useRef(AppState.currentState); useEffect(() => { const subscription = AppState.addEventListener("change", (nextAppState) => { - // console.log("oldAppState", appState.current); - // console.log("nextAppState", nextAppState); - // if ( appState.current.match(/inactive|background/) && nextAppState === "active" - // ) { console.log("App has come to the foreground"); //signOut(); } - // if (appState.current.match(/active/) && nextAppState === "inactive") { - // console.log("App is about to be inactive"); - // } if ( appState.current.match(/active|inactive/) && nextAppState === "background" ) { - // console.log("App is about to be background"); + //App is about to be background signOut(); } // if ( appState.current.match(/inactive/)) { console.log("App has come to the inactive"); } 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 712bc88..1337955 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 @@ -41,7 +41,7 @@ import { INSERT_NEW_TIME_TICKET } from "../../graphql/timetickets.queries"; import { useMutation, useQuery } from "@apollo/client"; import { QUERY_ACTIVE_TIME_TICKETS } from "../../graphql/timetickets.queries"; -import EmployeeClockedInList from "../time-ticket-lists/employee-clockedin-list.component"; +// import EmployeeClockedInList from "../time-ticket-lists/employee-clockedin-list.component"; import { useTranslation } from "react-i18next"; import ClockedinListItem from "../time-ticket-items/clockedin-list-item.component"; import SignOutButton from "../Buttons/employee-sign-out-button.component"; @@ -89,7 +89,6 @@ export function ScreenTimeTicketBrowser({ const [curSelClockIntoJob, setCurSelClockIntoJob] = useState(null); const handleFinish = async (values) => { - // console.log("handleFinish called in ScreenTimeTicketBrowser"); setLoadingClockIn(true); setError(null); @@ -131,15 +130,11 @@ export function ScreenTimeTicketBrowser({ ], }, }; - // console.info("INSERT_NEW_TIME_TICKET, variables for clockin. : ",tempVariablesObj?.variables?.timeTicketInput[0] ); const result = await insertTimeTicket(tempVariablesObj); - // console.log("insertTimeTicket, result :", result); setLoadingClockIn(false); if (!!result.errors) { - // console.log("insertTimeTicket, result.error :", result.errors); setError(JSON.stringify(result.errors)); } else { - // console.log("insertTimeTicket, result. :", result.data); setCurSelClockIntoJob(null); setCurrentSCC(null); } @@ -150,7 +145,7 @@ export function ScreenTimeTicketBrowser({ refetch(); setTimeout(() => { setRefreshing(false); - }, 1000); + }, 500); }, []); const [itemState, setItemState] = useState({ @@ -179,7 +174,6 @@ export function ScreenTimeTicketBrowser({ ); if (loadingATT) { - // console.log("loadingATT : "); setItemState((itemState) => ({ ...itemState, content: , @@ -187,14 +181,12 @@ export function ScreenTimeTicketBrowser({ return; } if (errorATT) { - // console.error("ErrorATT : ",errorATT); setItemState((itemState) => ({ ...itemState, content: , })); return; } - // console.log({ itemState: !!itemState }); return ( @@ -306,7 +298,7 @@ const MyItem = ({ itemState, style }) => { ) : !!itemState?.content ? ( itemState.content ) : ( - No Data + {t("timeticketbrowser.labels.nodata")} )} diff --git a/components/sign-out-button/sign-out-button.component.jsx b/components/sign-out-button/sign-out-button.component.jsx index 0e112da..49c4d1b 100644 --- a/components/sign-out-button/sign-out-button.component.jsx +++ b/components/sign-out-button/sign-out-button.component.jsx @@ -6,10 +6,8 @@ import { createStructuredSelector } from "reselect"; import { signOutStart } from "../../redux/user/user.actions"; import { employeeSignOut } from "../../redux/employee/employee.actions"; const mapStateToProps = createStructuredSelector({ - //currentUser: selectCurrentUser }); const mapDispatchToProps = (dispatch) => ({ - //setUserLanguage: language => dispatch(setUserLanguage(language)) signOutStart: () => dispatch(signOutStart()), signOut: () => dispatch(employeeSignOut()), }); diff --git a/components/time-ticket-items/clockedin-list-item.component.jsx b/components/time-ticket-items/clockedin-list-item.component.jsx index e10382e..33f54e8 100644 --- a/components/time-ticket-items/clockedin-list-item.component.jsx +++ b/components/time-ticket-items/clockedin-list-item.component.jsx @@ -13,18 +13,13 @@ const mapDispatchToProps = (dispatch) => ({ }); export function ClockedinListItem({ setTmTicketJobIdRedux, ticket }) { - // console.log("ClockedinListItem, ticket:",ticket); const { t } = useTranslation(); const navigation = useNavigation(); const makeNavToTimeTicketClockOff = () => ( - // console.log("makeNavToTimeTicketClockOff, checkHasDispatchCall:",setTmTicketJobIdRedux), setTmTicketJobIdRedux(ticket.job.id), navigation.navigate("TimeTicketClockOff", { - // jobId: ticket.jobid, //item.id, timeTicketId:ticket.id, - // handleOnDone:handleRefresh, - //completedCallback: refetch, }) ); diff --git a/components/time-ticket/screen-time-ticket-clockoff.component.jsx b/components/time-ticket/screen-time-ticket-clockoff.component.jsx index 1d52b62..3945cbf 100644 --- a/components/time-ticket/screen-time-ticket-clockoff.component.jsx +++ b/components/time-ticket/screen-time-ticket-clockoff.component.jsx @@ -1,5 +1,5 @@ import { Formik } from "formik"; -import React, { useEffect, useState, useRef, useCallback } from "react"; +import React, { useState, useRef, useCallback } from "react"; import { StyleSheet, Text, View, ScrollView, FlatList } from "react-native"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; @@ -8,8 +8,6 @@ import { Button, TextInput, Card, - Headline, - Subheading, } from "react-native-paper"; import CostCenterSelect from "../Selects/select-cost-center"; import { @@ -26,14 +24,9 @@ import { useMutation } from "@apollo/client"; import { selectCurrentTmTicketJobId } from "../../redux/app/app.selectors"; import ErrorDisplay from "../error-display/error-display.component"; import { timeTicketClockOutStart } from "../../redux/timetickets/timetickets.actions"; -import { logImEXEvent } from "../../firebase/firebase.analytics"; import axios from "axios"; import { useNavigation } from "@react-navigation/native"; import styles from "../styles"; -import StyleRepeater from "../style-repeater/style-repeater"; -// import { selectCurrentTimeTicketJobId } from "../../redux/timetickets/timetickets.selectors"; - -import { QUERY_ACTIVE_TIME_TICKETS } from "../../graphql/timetickets.queries"; import { RefreshControl } from "react-native"; @@ -57,17 +50,11 @@ export function TimeTicketClockOff({ route, }) { const costCenterDiff = useRef(0); - const setCostCenterDiff = (value) => { countRef.current = val; - // console.log(`Button clicked ${countRef.current} times`); }; - const navigation = useNavigation(); const { timeTicketId } = route.params; - // console.log("TimeTicketClockOff, timeTicketId :", timeTicketId); - // console.log( "TimeTicketClockOff, handleOnDone :", handleOnDone ); - const { t } = useTranslation(); const [loadingClockOut, setLoadingClockOut] = useState(false); const [loading, setLoading] = useState(false); @@ -79,30 +66,23 @@ export function TimeTicketClockOff({ }); const handleFinish = async (values) => { - logImEXEvent("TimeTicketClockOff_handleFinish"); - if ( !!values.actualhours && !!values.productivehours && !!currentSCC?.value ) { if (isNaN(values.actualhours) | isNaN(values.productivehours)) { - // console.log("actual hours is NAN!"); setLoadingClockOut(false); setError({ message: t("timeticketclockoff.errors.nan") }); return; } setError(null); - // console.log("all have values:"); } else { - // console.log("missing values!"); - setLoadingClockOut(false); + setLoadingClockOut(false); setError({ message: t("timeticketclockoff.errors.missingvalues") }); return; } - // console.log("TimeTicketClockOff, currentRestrictClaimableHoursFlag :", currentRestrictClaimableHoursFlag); if (!!currentRestrictClaimableHoursFlag) { - // console.log("TimeTicketClockOff, currentRestrictClaimableHoursFlag I am here:", currentRestrictClaimableHoursFlag); if (values.productivehours > costCenterDiff.current) { setLoadingClockOut(false); setError({ @@ -145,23 +125,15 @@ export function TimeTicketClockOff({ }, }, }; - // console.log("TimeTicketClockOff, tempcallobj :", tempcallobj); - - //after obj is good add below to make call + setLoadingClockOut(true); const result = await updateTimeticket(tempcallobj); - - //after call results are retuning add handling below for cases - // console.log("updateTimeticket, result :", result); setLoadingClockOut(false); if (!!result.errors) { - // console.log("updateTimeticket, result.error :", result.errors); setError(JSON.stringify(result.errors)); } else { - // console.log("updateTimeticket, result :", result.data); navigation.goBack(); } - //if (completedCallback) completedCallback(); }; const onRefresh = useCallback(() => { @@ -169,7 +141,7 @@ export function TimeTicketClockOff({ // refetch(); setTimeout(() => { setLoading(false); - }, 1000); + }, 500); }, []); return ( diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index f30f46a..3a69666 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -1,12 +1,11 @@ import { Formik } from "formik"; -import React, { useRef, useState } from "react"; -import { StyleSheet, Text, View, ScrollView, RefreshControl } from "react-native"; +import React, { useRef, useState,useCallback } from "react"; +import { StyleSheet, Text, View, ScrollView, RefreshControl,FlatList } from "react-native"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { Button, TextInput, Card } from "react-native-paper"; import CostCenterSelect from "../Selects/select-cost-center"; -import { JobIdSearchSelect } from "../Selects/select-job-id"; import DateTimePickerModal from "react-native-modal-datetime-picker"; import { selectCurrentEmployee, @@ -17,21 +16,15 @@ import { selectBodyshop, selectRestrictClaimableHoursFlag, } from "../../redux/user/user.selectors"; -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"; import { INSERT_NEW_TIME_TICKET } from "../../graphql/timetickets.queries"; import { useMutation } from "@apollo/client"; -import axios from "axios"; -import { logImEXEvent } from "../../firebase/firebase.analytics"; import moment from "moment"; import { useNavigation } from "@react-navigation/native"; import styles from "../styles"; -import StyleRepeater from "../style-repeater/style-repeater"; -import { FlatList } from "react-native"; import JobSearchAndSelectModal from "../Modals/JobSearchAndSelectModal"; const mapStateToProps = createStructuredSelector({ @@ -41,7 +34,6 @@ const mapStateToProps = createStructuredSelector({ currentEmployeeFullName: selectEmployeeFullName, currentRestrictClaimableHoursFlag: selectRestrictClaimableHoursFlag, }); -// const mapDispatchToProps = (dispatch) => ({}); export function TimeTicketCreate({ currentEmployee, @@ -76,15 +68,8 @@ export function TimeTicketCreate({ const [insertTicket] = useMutation(INSERT_NEW_TIME_TICKET); const handleFinish = async (values) => { - logImEXEvent("handleFinish_called_in_TimeTicketCreate"); - // console.log("handleFinish called in TimeTicketCreate"); setError(null); setLoadingCreate(true); - - // console.log("insertTicket, currentSCC :", currentSCC); - // console.log("insertTicket, currentSCC :", currentSJobId); - // console.log("insertTicket, values :", values); - if ( !!currentSCC?.value && !!curSelClockIntoJob?.id && @@ -110,7 +95,6 @@ export function TimeTicketCreate({ } if (!!currentRestrictClaimableHoursFlag) { - // console.log("TimeTicketClockOff, currentRestrictClaimableHoursFlag I am here:", currentRestrictClaimableHoursFlag); if (values.productivehours > costCenterDiff.current) { setLoadingCreate(false); setError({ @@ -119,7 +103,7 @@ export function TimeTicketCreate({ return; } } - + const tempVariablesObj = { variables: { timeTicketInput: [ @@ -157,19 +141,8 @@ export function TimeTicketCreate({ ], }, }; - // clockoff: undefined, - // clockon: undefined, - // memo: undefined, - // console.log("insertTicket, tempVariablesObj. :", tempVariablesObj?.variables?.timeTicketInput[0]); - - //after obj is good add below to make call - - const result = await insertTicket(tempVariablesObj); //.catch(handleMutationError); - - // console.log(" result : ", result); - // //after call results are retuning add handling below for cases - // console.log("insertTicket, result :", result?.data?.insert_timetickets?.returning[0]); + const result = await insertTicket(tempVariablesObj); setLoadingCreate(false); if (!!result.errors) { // console.log("insertTicket, result.error :", result.errors); @@ -185,7 +158,7 @@ export function TimeTicketCreate({ // refetch(); setTimeout(() => { setLoading(false); - }, 1000); + }, 500); }, []); return ( @@ -206,20 +179,13 @@ export function TimeTicketCreate({ > {({ handleChange, handleBlur, handleSubmit, values }) => ( - {/* */} - + convertedOnly={true} + /> 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 1337955..b3ba682 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 @@ -49,6 +49,7 @@ import AddTimeTicketButton from "../Buttons/create-time-ticket-button.component" import KeyboardAvoidingComponent from "../keyboards/KeyboardAvoidingComponent"; import JobSearchAndSelectModal from "../Modals/JobSearchAndSelectModal"; +import { useNavigation } from "@react-navigation/native"; const mapStateToProps = createStructuredSelector({ currentEmployee: selectCurrentEmployee, @@ -86,6 +87,7 @@ export function ScreenTimeTicketBrowser({ refetchQueries: ["QUERY_ACTIVE_TIME_TICKETS"], }); + const navigation = useNavigation(); const [curSelClockIntoJob, setCurSelClockIntoJob] = useState(null); const handleFinish = async (values) => { @@ -196,7 +198,7 @@ export function ScreenTimeTicketBrowser({ } + right={(props) => } /> {currentEmployeeFullName && ( @@ -213,32 +215,32 @@ export function ScreenTimeTicketBrowser({ ( - // - // - // - // - // )} + right={(props) => ( + + + {/* */} + + )} /> - No Data + {t("timeticketbrowser.labels.nodata")} } /> @@ -288,6 +290,7 @@ export function ScreenTimeTicketBrowser({ } const MyItem = ({ itemState, style }) => { + const { t } = useTranslation(); const items = itemState?.data; return ( From 60e6fd14a3975cc81e0dc0fbf5722f9bf1ab27e3 Mon Sep 17 00:00:00 2001 From: jfrye122 Date: Wed, 26 Jul 2023 08:38:19 -0400 Subject: [PATCH 105/105] small fixes to style --- components/screen-main/screen-main.component.jsx | 6 ------ .../time-ticket/screen-time-ticket-clockoff.component.jsx | 3 +++ .../time-ticket/screen-time-ticket-create.component.jsx | 3 +++ 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/screen-main/screen-main.component.jsx b/components/screen-main/screen-main.component.jsx index c28af6c..8b97379 100644 --- a/components/screen-main/screen-main.component.jsx +++ b/components/screen-main/screen-main.component.jsx @@ -160,12 +160,6 @@ const TimeTicketBrowserStackNavigator = connect( name="TimeTicketBrowser" options={{ title: i18n.t("timeticketbrowser.titles.timeticketbrowsertab"), - headerRight: () => ( - <> - - - - ), }} component={ScreenTimeTicketBrowser} /> diff --git a/components/time-ticket/screen-time-ticket-clockoff.component.jsx b/components/time-ticket/screen-time-ticket-clockoff.component.jsx index 3945cbf..ad3c424 100644 --- a/components/time-ticket/screen-time-ticket-clockoff.component.jsx +++ b/components/time-ticket/screen-time-ticket-clockoff.component.jsx @@ -190,7 +190,9 @@ export function TimeTicketClockOff({ {error ? ( ) : null} + + )} diff --git a/components/time-ticket/screen-time-ticket-create.component.jsx b/components/time-ticket/screen-time-ticket-create.component.jsx index 3a69666..f289e3e 100644 --- a/components/time-ticket/screen-time-ticket-create.component.jsx +++ b/components/time-ticket/screen-time-ticket-create.component.jsx @@ -245,6 +245,8 @@ export function TimeTicketCreate({ {error ? ( ) : null} + + + )}