145 lines
5.0 KiB
TypeScript
145 lines
5.0 KiB
TypeScript
import {useMemo} from "react";
|
||
import {MRT_ColumnDef} from "mantine-react-table";
|
||
import {getDayOfWeek} from "../../../../../shared/lib/date.ts";
|
||
import {Box, Flex, NumberInput, rem} from "@mantine/core";
|
||
import {isNumber, last} from "lodash";
|
||
import {processSelectedCells} from "../../../../../shared/lib/interpolateCells.ts";
|
||
import {TimeTrackingData} from "../../../../../client";
|
||
import dayjs from "dayjs";
|
||
|
||
export type EmployeeData = {
|
||
name: string;
|
||
userId: number;
|
||
totalAmount: number;
|
||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||
// @ts-expect-error
|
||
data?: TimeTrackingData[],
|
||
[key: string]: number | string;
|
||
};
|
||
type Props = {
|
||
month: Date;
|
||
data: EmployeeData[];
|
||
onUpdate: (date: Date, userId: number, value: number) => void,
|
||
selectedCells: string[];
|
||
setSelectedCells: (cells: string[]) => void
|
||
selectedBoundaries: [Date | null, Date | null];
|
||
range: dayjs.Dayjs[];
|
||
}
|
||
const useWorkTableColumns = ({
|
||
month,
|
||
onUpdate,
|
||
data,
|
||
selectedCells,
|
||
setSelectedCells,
|
||
selectedBoundaries,
|
||
range
|
||
}: Props) => {
|
||
const totalAmount = useMemo(() => {
|
||
return data.reduce((acc, value) => {
|
||
if (value.data) {
|
||
const sum = value.data.reduce((innerAcc, item) => innerAcc + item.amount, 0);
|
||
return acc + sum;
|
||
}
|
||
return acc;
|
||
}, 0);
|
||
}, [data, month, selectedCells, selectedBoundaries]);
|
||
const getBorderStyles = (cellId: string) => {
|
||
if (selectedCells.length <= 1) return {}
|
||
if (selectedCells[0] === cellId)
|
||
return {
|
||
borderTopLeftRadius: rem(20),
|
||
borderBottomLeftRadius: rem(20),
|
||
}
|
||
else if (last(selectedCells) === cellId)
|
||
return {
|
||
borderTopRightRadius: rem(20),
|
||
borderBottomRightRadius: rem(20),
|
||
}
|
||
return {}
|
||
}
|
||
|
||
return useMemo<MRT_ColumnDef<EmployeeData>[]>(() => [
|
||
{
|
||
accessorKey: "name",
|
||
header: "ФИО"
|
||
},
|
||
|
||
...range.map(date => ({
|
||
size: 80,
|
||
accessorKey: date.date().toString(),
|
||
header: date.date().toString(),
|
||
enableSorting: false,
|
||
enableColumnActions: false,
|
||
Header: (
|
||
<Flex
|
||
align={"center"}
|
||
direction={"column"}>
|
||
<Box>
|
||
{date.date()}
|
||
</Box>
|
||
<Box>
|
||
{getDayOfWeek(date.day())}
|
||
</Box>
|
||
</Flex>
|
||
),
|
||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||
// @ts-expect-error
|
||
mantineTableBodyCellProps: ({cell}) => ({
|
||
style: selectedCells.includes(cell.id) ? {
|
||
backgroundColor: "var(--mantine-primary-color-filled)",
|
||
...getBorderStyles(cell.id)
|
||
} : {},
|
||
onClick: () => {
|
||
const result = processSelectedCells(selectedCells, cell.id);
|
||
setSelectedCells(result);
|
||
},
|
||
|
||
}),
|
||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||
// @ts-expect-error
|
||
Cell: ({cell, row}) => {
|
||
return (
|
||
<Flex direction={"column"}>
|
||
<NumberInput
|
||
// key={row.original.name + date.date().toString()}
|
||
onChange={event => isNumber(event) && onUpdate(date.toDate(), row.original.userId, event)}
|
||
styles={{input: {textAlign: "center"}}}
|
||
hideControls
|
||
value={cell.renderValue()}
|
||
/>
|
||
</Flex>
|
||
);
|
||
}
|
||
})),
|
||
{
|
||
header: "Всего часов",
|
||
Cell: ({row}) => {
|
||
return Object.entries(row.original).reduce((acc, [key, value]) => {
|
||
if (isNaN(parseInt(key)) || !isNumber(value)) return acc;
|
||
acc += value;
|
||
return acc;
|
||
}, 0);
|
||
},
|
||
},
|
||
{
|
||
accessorKey: "totalAmount",
|
||
header: "Итоговая сумма заработка",
|
||
|
||
Cell: ({row}) => {
|
||
return (row.original.data || []).reduce((acc, value) => {
|
||
acc += value.amount;
|
||
return acc;
|
||
}, 0);
|
||
},
|
||
Footer: (
|
||
<Flex>
|
||
Всего: {totalAmount.toLocaleString("ru-RU")}
|
||
</Flex>
|
||
)
|
||
},
|
||
|
||
|
||
], [month, selectedCells, selectedBoundaries, totalAmount]);
|
||
}
|
||
|
||
export default useWorkTableColumns; |