import { EditFilled, SyncOutlined } from "@ant-design/icons"; import { useSplitTreatments } from "@splitsoftware/splitio-react"; import { Button, Card, Checkbox, Space, Table } from "antd"; import React, { useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { Link } from "react-router-dom"; import { createStructuredSelector } from "reselect"; import { setModalContext } from "../../redux/modals/modals.actions"; import { selectAuthLevel, selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors"; import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter"; import { onlyUnique } from "../../utils/arrayHelper"; import dayjs from "../../utils/day"; import { alphaSort, dateSort } from "../../utils/sorters"; import { HasRbacAccess } from "../rbac-wrapper/rbac-wrapper.component"; import TimeTicketEnterButton from "../time-ticket-enter-button/time-ticket-enter-button.component"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, authLevel: selectAuthLevel, currentUser: selectCurrentUser }); const mapDispatchToProps = (dispatch) => ({ setTimeTicketTaskContext: (context) => dispatch(setModalContext({ context: context, modal: "timeTicketTask" })) }); export default connect(mapStateToProps, mapDispatchToProps)(TimeTicketList); export function TimeTicketList({ bodyshop, setTimeTicketTaskContext, authLevel, currentUser, disabled, loading, timetickets, refetch, techConsole, jobId, extra }) { const [state, setState] = useState({ sortedInfo: {}, filteredInfo: { text: "" } }); const { t } = useTranslation(); const { treatments: { Enhanced_Payroll } } = useSplitTreatments({ attributes: {}, names: ["Enhanced_Payroll"], splitKey: bodyshop.imexshopid }); const canEditCommittedTimeTickets = HasRbacAccess({ bodyshop, authLevel, action: "timetickets:editcommitted" }); const canEditTimeTickets = HasRbacAccess({ bodyshop, authLevel, action: "timetickets:edit" }); const canEditShiftTickets = HasRbacAccess({ bodyshop, authLevel, action: "timetickets:shiftedit" }); const totals = useMemo(() => { if (timetickets) return timetickets.reduce( (acc, val) => { acc.productivehrs = acc.productivehrs + val.productivehrs; acc.actualhrs = acc.actualhrs + val.actualhrs; return acc; }, { productivehrs: 0, actualhrs: 0 } ); return { productivehrs: 0, actualhrs: 0 }; }, [timetickets]); const isDisabled = (record) => { if (disabled === true || !record.id) return true; const isShiftTicket = !record.ciecacode; const isCommitted = record.committed_at; if (isShiftTicket) { return !(canEditShiftTickets && (!isCommitted || canEditCommittedTimeTickets)); } return !(canEditTimeTickets && (!isCommitted || canEditCommittedTimeTickets)); }; const columns = [ ...(Enhanced_Payroll.treatment === "on" ? [ { title: t("timetickets.fields.committed"), dataIndex: "committed_at", key: "committed_at", render: (text, record) => } ] : []), { title: t("timetickets.fields.date"), dataIndex: "date", key: "date", sorter: (a, b) => dateSort(a.date, b.date), sortOrder: state.sortedInfo.columnKey === "date" && state.sortedInfo.order, render: (text, record) => {record.date} }, { title: t("timetickets.fields.employee"), dataIndex: "employee", key: "employee", sorter: (a, b) => alphaSort(a.employee.last_name, b.employee.last_name), sortOrder: state.sortedInfo.columnKey === "employee" && state.sortedInfo.order, render: (text, record) => `${record.employee.first_name} ${record.employee.last_name}`, filters: timetickets .map((l) => l.employeeid) .filter(onlyUnique) .map((s) => { return { text: (() => { const emp = bodyshop.employees.find((e) => e.id === s); return `${emp?.first_name} ${emp?.last_name}`; })(), // value: [s] }; }) || [], onFilter: (value, record) => value.includes(record.employeeid) }, { title: t("timetickets.fields.cost_center"), dataIndex: "cost_center", key: "cost_center", sorter: (a, b) => alphaSort(a.cost_center, b.cost_center), render: (text, record) => record.cost_center === "timetickets.labels.shift" ? t(record.cost_center) : record.cost_center, sortOrder: state.sortedInfo.columnKey === "cost_center" && state.sortedInfo.order, filters: timetickets .map((l) => l.cost_center) .filter(onlyUnique) .map((s) => { return { text: s === "timetickets.labels.shift" ? t(s) : s, //|| "No Status*", value: [s] }; }) || [], onFilter: (value, record) => value.includes(record.cost_center) }, ...(jobId ? [] : [ { title: t("jobs.fields.ro_number"), dataIndex: "ro_number", key: "ro_number", sorter: (a, b) => alphaSort(a.job && a.job.ro_number, b.job && b.job.ro_number), sortOrder: state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order, render: (text, record) => record.job && {record.job.ro_number || "N/A"} } ]), { title: t("timetickets.fields.productivehrs"), dataIndex: "productivehrs", key: "productivehrs", sorter: (a, b) => a.productivehrs - b.productivehrs, sortOrder: state.sortedInfo.columnKey === "productivehrs" && state.sortedInfo.order }, ...(Enhanced_Payroll.treatment === "on" ? [] : [ { title: t("timetickets.fields.actualhrs"), dataIndex: "actualhrs", key: "actualhrs", sorter: (a, b) => a.actualhrs - b.actualhrs, sortOrder: state.sortedInfo.columnKey === "actualhrs" && state.sortedInfo.order } ]), { title: t("timetickets.fields.memo"), dataIndex: "memo", key: "memo", sorter: (a, b) => alphaSort(a.memo, b.memo), sortOrder: state.sortedInfo.columnKey === "memo" && state.sortedInfo.order, render: (text, record) => (record.memo?.startsWith("timetickets.labels") ? t(record.memo) : record.memo) }, ...(Enhanced_Payroll.treatment === "on" ? [ { title: t("timetickets.fields.task_name"), dataIndex: "task_name", key: "task_name", sorter: (a, b) => alphaSort(a.task_name, b.task_name), sortOrder: state.sortedInfo.columnKey === "task_name" && state.sortedInfo.order } ] : []), ...(Enhanced_Payroll.treatment === "on" ? [] : [ { title: t("timetickets.fields.clockon"), dataIndex: "clockon", key: "clockon", render: (text, record) => {record.clockon} }, { title: t("timetickets.fields.clockoff"), dataIndex: "clockoff", key: "clockoff", render: (text, record) => {record.clockoff} }, { title: t("timetickets.fields.clockhours"), dataIndex: "clockhours", key: "clockhours", render: (text, record) => { if (record.clockoff && record.clockon) return
{dayjs(record.clockoff).diff(dayjs(record.clockon), "hour", true).toFixed(2)}
; else { return null; } } } ]), { title: t("timetickets.fields.created_by"), dataIndex: "created_by", key: "created_by", sorter: (a, b) => alphaSort(a.created_by, b.created_by), sortOrder: state.sortedInfo.columnKey === "created_by" && state.sortedInfo.order, render: (text, record) => record.created_by }, // { // title: "Pay", // dataIndex: "pay", // key: "pay", // render: (text, record) => // Dinero({ amount: Math.round(record.rate * 100) }) // .multiply(record.flat_rate ? record.productivehrs : record.actualhrs) // .toFormat("$0.00"), // }, { title: t("general.labels.actions"), dataIndex: "actions", key: "actions", render: (text, record) => ( {techConsole && ( )} {!techConsole && ( )} ) } ]; const handleTableChange = (pagination, filters, sorter) => { setState({ ...state, filteredInfo: filters, sortedInfo: sorter }); }; return ( {jobId && bodyshop.md_tasks_presets.enable_tasks && ( )} {jobId && (techConsole ? null : ( {t("timetickets.actions.enter")} ))} {extra} } > { if (Enhanced_Payroll.treatment === "on") return null; if (Enhanced_Payroll.treatment === "off") return ( {t("general.labels.totals")} {totals.productivehrs.toFixed(1)} {totals.actualhrs.toFixed(1)} {totals.actualhrs === 0 || !totals.actualhrs ? "∞" : `${((totals.productivehrs / totals.actualhrs) * 100).toFixed( 2 )}% ${t("timetickets.labels.efficiency")}`} ); }} /> ); }