import { EditFilled } from "@ant-design/icons"; import { Button, Card, Checkbox, Space, Table } from "antd"; import moment from "moment"; 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, } from "../../redux/user/user.selectors"; import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter"; import { onlyUnique } from "../../utils/arrayHelper"; import { alphaSort, dateSort } from "../../utils/sorters"; import RbacWrapper, { 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, }); const mapDispatchToProps = (dispatch) => ({ setTimeTicketTaskContext: (context) => dispatch(setModalContext({ context: context, modal: "timeTicketTask" })), }); export default connect(mapStateToProps, mapDispatchToProps)(TimeTicketList); export function TimeTicketList({ bodyshop, setTimeTicketTaskContext, authLevel, disabled, loading, timetickets, refetch, techConsole, jobId, extra, }) { const [state, setState] = useState({ sortedInfo: {}, filteredInfo: { text: "" }, }); const { t } = useTranslation(); 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 columns = [ { 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), }, { 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, }, { 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.clockon || record.clockoff ? t(record.memo) : record.memo, }, { 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 (
{moment(record.clockoff) .diff(moment(record.clockon), "hours", true) .toFixed(2)}
); else { return null; } }, }, // { // 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 && ( { return
; }} > )} ), }, ]; const handleTableChange = (pagination, filters, sorter) => { setState({ ...state, filteredInfo: filters, sortedInfo: sorter }); }; return ( { // } {bodyshop.md_tasks_presets.enable_tasks && ( )} {jobId && (techConsole ? null : ( {t("timetickets.actions.enter")} ))} {extra} } > { 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")}`} ); }} /> ); }