* esm * wip * wip * wip * wip * wip * wip * subscription notice * wip * wip * wip * fix envs * fix: update docker build * fix * esm/types * delete dashboard :D * add patches to dockerfiles * update packages + catalogs + ts * wip * remove native libs * ts * improvements * fix redirects and fetching session * try fix favicon * fixes * fix * order and resize reportds within a dashboard * improvements * wip * added userjot to dashboard * fix * add op * wip * different cache key * improve date picker * fix table * event details loading * redo onboarding completely * fix login * fix * fix * extend session, billing and improve bars * fix * reduce price on 10M
93 lines
2.4 KiB
TypeScript
93 lines
2.4 KiB
TypeScript
import { Widget, WidgetBody } from '@/components/widget';
|
|
import { cn } from '@/utils/cn';
|
|
import {
|
|
addMonths,
|
|
eachDayOfInterval,
|
|
endOfMonth,
|
|
format,
|
|
formatISO,
|
|
isSameMonth,
|
|
startOfMonth,
|
|
subMonths,
|
|
} from 'date-fns';
|
|
import { ActivityIcon, ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';
|
|
import { useState } from 'react';
|
|
import {
|
|
WidgetAbsoluteButtons,
|
|
WidgetHead,
|
|
WidgetTitle,
|
|
} from '../overview/overview-widget';
|
|
import { Button } from '../ui/button';
|
|
|
|
type Props = {
|
|
data: { count: number; date: string }[];
|
|
};
|
|
|
|
const MonthCalendar = ({
|
|
month,
|
|
data,
|
|
}: { month: Date; data: Props['data'] }) => (
|
|
<div>
|
|
<div className="mb-2 text-sm">{format(month, 'MMMM yyyy')}</div>
|
|
<div className="-m-1 grid grid-cols-7 gap-1 p-1">
|
|
{eachDayOfInterval({
|
|
start: startOfMonth(month),
|
|
end: endOfMonth(month),
|
|
}).map((date) => {
|
|
const hit = data.find((item) =>
|
|
item.date.includes(formatISO(date, { representation: 'date' })),
|
|
);
|
|
return (
|
|
<div
|
|
key={date.toISOString()}
|
|
className={cn(
|
|
'aspect-square w-full rounded',
|
|
hit ? 'bg-highlight' : 'bg-def-200',
|
|
)}
|
|
/>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
export const ProfileActivity = ({ data }: Props) => {
|
|
const [startDate, setStartDate] = useState(startOfMonth(new Date()));
|
|
|
|
return (
|
|
<Widget className="w-full">
|
|
<WidgetHead className="row justify-between relative">
|
|
<WidgetTitle icon={ActivityIcon}>Activity</WidgetTitle>
|
|
<WidgetAbsoluteButtons>
|
|
<Button
|
|
variant="outline"
|
|
size="icon"
|
|
onClick={() => setStartDate(subMonths(startDate, 1))}
|
|
>
|
|
<ChevronLeftIcon size={14} />
|
|
</Button>
|
|
<Button
|
|
variant="outline"
|
|
size="icon"
|
|
disabled={isSameMonth(startDate, new Date())}
|
|
onClick={() => setStartDate(addMonths(startDate, 1))}
|
|
>
|
|
<ChevronRightIcon size={14} />
|
|
</Button>
|
|
</WidgetAbsoluteButtons>
|
|
</WidgetHead>
|
|
<WidgetBody>
|
|
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
|
{[3, 2, 1, 0].map((offset) => (
|
|
<MonthCalendar
|
|
key={offset}
|
|
month={subMonths(startDate, offset)}
|
|
data={data}
|
|
/>
|
|
))}
|
|
</div>
|
|
</WidgetBody>
|
|
</Widget>
|
|
);
|
|
};
|