Files
edr-platform/apps/edr-hr-web/src/features/leave/components/BalanceCards.tsx
2026-08-25 00:11:39 +03:00

88 lines
2.9 KiB
TypeScript

import { Card, Group, Progress, SimpleGrid, Text, Tooltip } from "@mantine/core";
import { useTranslation } from "react-i18next";
import { localized } from "@/shared/lib/localizedName";
import type { LeaveBalance } from "../types";
/**
* Balances at a glance.
*
* The bar shows what has been used against what was granted, because "11 of 16"
* answers the question faster than "11". Types with nothing granted are still
* shown — an employee who is not yet eligible needs to see that the leave exists
* and is at zero, not have it hidden and wonder whether the system knows about it.
*/
export function BalanceCards({
balances,
onOpen,
}: {
balances: LeaveBalance[];
onOpen?: (balance: LeaveBalance) => void;
}) {
const { i18n } = useTranslation();
return (
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
{balances.map((balance) => {
const used = balance.grantedDays > 0 ? (balance.takenDays / balance.grantedDays) * 100 : 0;
const low = balance.grantedDays > 0 && balance.availableDays <= 0;
return (
<Card
key={balance.leaveTypeId}
withBorder
radius="md"
padding="md"
style={{ cursor: onOpen ? "pointer" : undefined }}
onClick={() => onOpen?.(balance)}
>
<Group justify="space-between" align="flex-start" wrap="nowrap">
<div>
<Text size="sm" fw={500}>
{localized(balance.name, i18n.language) || balance.code}
</Text>
<Text size="xs" c="dimmed">
{balance.leaveYearStart} {balance.leaveYearEnd}
</Text>
</div>
<Tooltip label="Days still available">
<Text size="xl" fw={700} c={low ? "red" : undefined}>
{balance.availableDays}
</Text>
</Tooltip>
</Group>
<Progress
mt="sm"
size="sm"
value={Math.min(100, used)}
color={low ? "red" : "blue"}
/>
<Group justify="space-between" mt={6}>
<Text size="xs" c="dimmed">
{balance.takenDays} taken of {balance.grantedDays}
</Text>
{balance.adjustmentDays !== 0 && (
<Text size="xs" c="grape">
{balance.adjustmentDays > 0 ? "+" : ""}
{balance.adjustmentDays} adjusted
</Text>
)}
</Group>
{balance.carriedOverDays > 0 && (
<Text size="xs" c="dimmed" mt={4}>
includes {balance.carriedOverDays} carried over
{balance.carryOverExpiresOn
? `, lapsing ${balance.carryOverExpiresOn}`
: ""}
</Text>
)}
</Card>
);
})}
</SimpleGrid>
);
}