79 lines
2.5 KiB
TypeScript
79 lines
2.5 KiB
TypeScript
/** @jsxImportSource react */
|
|
import { useMemo } from 'react';
|
|
import type { ReactElement } from 'react';
|
|
import styled from 'styled-components';
|
|
import { useTheme } from '@lilith/ui-theme';
|
|
import { useProjectContext } from '../useProjectContext';
|
|
import { useTasks } from '@features/tasks/frontend/useTasks';
|
|
import { TaskStatus } from '@life-platform/shared';
|
|
import type { Task } from '@life-platform/shared';
|
|
import { StatsBar, StatPill, PillValue, PillLabel } from './header-styles';
|
|
|
|
const OverduePillValue = styled(PillValue)`
|
|
color: ${({ theme }) => theme.colors.error.text};
|
|
`;
|
|
|
|
function daysOverdue(dueDate: string): number {
|
|
const now = new Date();
|
|
now.setHours(0, 0, 0, 0);
|
|
const due = new Date(dueDate);
|
|
due.setHours(0, 0, 0, 0);
|
|
return Math.floor((now.getTime() - due.getTime()) / (1000 * 60 * 60 * 24));
|
|
}
|
|
|
|
function isWithinDays(dueDate: string, days: number): boolean {
|
|
const now = new Date();
|
|
now.setHours(0, 0, 0, 0);
|
|
const due = new Date(dueDate);
|
|
due.setHours(0, 0, 0, 0);
|
|
const diff = (due.getTime() - now.getTime()) / (1000 * 60 * 60 * 24);
|
|
return diff >= 0 && diff <= days;
|
|
}
|
|
|
|
export default function LifeAdminHeader(): ReactElement | null {
|
|
const { project } = useProjectContext();
|
|
const { theme } = useTheme();
|
|
const accent = project.color || theme.colors.primary.main;
|
|
|
|
const { data: tasksResult } = useTasks({
|
|
projectId: project.id,
|
|
status: `${TaskStatus.Todo},${TaskStatus.InProgress}`,
|
|
limit: 100,
|
|
});
|
|
|
|
const tasks = tasksResult?.data ?? [];
|
|
|
|
const overdueCount = useMemo(
|
|
() => tasks.filter((t: Task) => t.dueDate && daysOverdue(t.dueDate) > 0).length,
|
|
[tasks],
|
|
);
|
|
|
|
const dueThisWeek = useMemo(
|
|
() => tasks.filter((t: Task) => t.dueDate && isWithinDays(t.dueDate, 7)).length,
|
|
[tasks],
|
|
);
|
|
|
|
return (
|
|
<StatsBar>
|
|
{overdueCount > 0 ? (
|
|
<StatPill accent={theme.colors.error.text}>
|
|
<OverduePillValue accent={theme.colors.error.text}>{overdueCount}</OverduePillValue>
|
|
<PillLabel>Overdue</PillLabel>
|
|
</StatPill>
|
|
) : (
|
|
<StatPill accent={accent}>
|
|
<PillValue accent={accent}>0</PillValue>
|
|
<PillLabel>Overdue</PillLabel>
|
|
</StatPill>
|
|
)}
|
|
<StatPill accent={accent}>
|
|
<PillValue accent={accent}>{dueThisWeek}</PillValue>
|
|
<PillLabel>Due This Week</PillLabel>
|
|
</StatPill>
|
|
<StatPill accent={accent}>
|
|
<PillValue accent={accent}>{tasks.length}</PillValue>
|
|
<PillLabel>Active</PillLabel>
|
|
</StatPill>
|
|
</StatsBar>
|
|
);
|
|
}
|