Files
bodyshop/client/src/components/time-ticket-list/time-ticket-list.component.jsx
2021-04-07 17:39:46 -07:00

251 lines
7.5 KiB
JavaScript

import { Card, Space, Table } from "antd";
import moment from "moment";
import React, { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { onlyUnique } from "../../utils/arrayHelper";
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
import { alphaSort } from "../../utils/sorters";
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
import TimeTicketEnterButton from "../time-ticket-enter-button/time-ticket-enter-button.component";
export default function TimeTicketList({
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.date"),
dataIndex: "date",
key: "date",
sorter: (a, b) => (a.date = b.date),
sortOrder:
state.sortedInfo.columnKey === "date" && state.sortedInfo.order,
render: (text, record) => <DateFormatter>{record.date}</DateFormatter>,
},
{
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 === "vin" && state.sortedInfo.order,
render: (text, record) =>
`${record.employee.first_name} ${record.employee.last_name}`,
},
{
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 === "status" && state.sortedInfo.order,
filters:
timetickets
.map((l) => l.cost_center)
.filter(onlyUnique)
.map((s) => {
return {
text: s, //|| "No Status*",
value: [s],
};
}) || [],
onFilter: (value, record) => value.includes(record.cost_center),
},
{
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) => 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",
sorter: (a, b) => a.clockon - b.clockon,
sortOrder:
state.sortedInfo.columnKey === "clockon" && state.sortedInfo.order,
render: (text, record) => (
<DateTimeFormatter>{record.clockon}</DateTimeFormatter>
),
},
{
title: t("timetickets.fields.clockoff"),
dataIndex: "clockoff",
key: "clockoff",
sorter: (a, b) => a.clockoff - b.clockoff,
sortOrder:
state.sortedInfo.columnKey === "clockoff" && state.sortedInfo.order,
render: (text, record) => (
<DateTimeFormatter>{record.clockoff}</DateTimeFormatter>
),
},
{
title: t("timetickets.fields.clockhours"),
dataIndex: "clockoff",
key: "clockoff",
sorter: (a, b) => a.clockoff - b.clockoff,
sortOrder:
state.sortedInfo.columnKey === "clockoff" && state.sortedInfo.order,
render: (text, record) => {
if (record.clockoff && record.clockon)
return (
<div>
{moment(record.clockoff)
.diff(moment(record.clockon), "hours", true)
.toFixed(2)}
</div>
);
else {
return null;
}
},
},
{
title: t("general.labels.actions"),
dataIndex: "actions",
key: "actions",
render: (text, record) => (
<Space wrap>
{techConsole && (
<TimeTicketEnterButton
actions={{ refetch }}
context={{ id: record.id, timeticket: record }}
disabled={!!!record.job || disabled}
>
{t("general.actions.edit")}
</TimeTicketEnterButton>
)}
{!techConsole && (
<RbacWrapper
action="timetickets:edit"
noauth={() => {
return <div />;
}}
>
<TimeTicketEnterButton
actions={{ refetch }}
context={{
id: record.id,
timeticket: record,
}}
disabled={!!!record.jobid || disabled}
>
{t("general.actions.edit")}
</TimeTicketEnterButton>
</RbacWrapper>
)}
</Space>
),
},
];
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
return (
<Card
title={t("timetickets.labels.timetickets")}
extra={
<Space wrap>
{jobId &&
(techConsole ? null : (
<TimeTicketEnterButton
actions={{ refetch }}
context={{ jobId: jobId }}
>
{t("timetickets.actions.enter")}
</TimeTicketEnterButton>
))}
{extra}
</Space>
}
>
<Table
loading={loading}
columns={columns}
rowKey="id"
scroll={{
x: true,
}}
dataSource={timetickets}
onChange={handleTableChange}
summary={() => {
return (
<Table.Summary.Row>
<Table.Summary.Cell>
{t("general.labels.totals")}
</Table.Summary.Cell>
<Table.Summary.Cell />
<Table.Summary.Cell />
<Table.Summary.Cell>{totals.productivehrs}</Table.Summary.Cell>
<Table.Summary.Cell>{totals.actualhrs}</Table.Summary.Cell>
<Table.Summary.Cell>
{totals.actualhrs === 0 || !totals.actualhrs
? "∞"
: `${(
(totals.productivehrs / totals.actualhrs) *
100
).toFixed(2)}% ${t("timetickets.labels.efficiency")}`}
</Table.Summary.Cell>
<Table.Summary.Cell />
<Table.Summary.Cell />
<Table.Summary.Cell />
</Table.Summary.Row>
);
}}
/>
</Card>
);
}