|
|
|
|
@ -1,5 +1,6 @@
|
|
|
|
|
import { Tooltip } from "@mui/joy";
|
|
|
|
|
import dayjs from "dayjs";
|
|
|
|
|
import { observer } from "mobx-react-lite";
|
|
|
|
|
import { memo, useMemo } from "react";
|
|
|
|
|
import { workspaceStore } from "@/store/v2";
|
|
|
|
|
import type { ActivityCalendarProps, CalendarDay } from "@/types/statistics";
|
|
|
|
|
@ -67,104 +68,106 @@ const CalendarCell = memo(
|
|
|
|
|
|
|
|
|
|
CalendarCell.displayName = "CalendarCell";
|
|
|
|
|
|
|
|
|
|
export const ActivityCalendar = memo((props: ActivityCalendarProps) => {
|
|
|
|
|
const t = useTranslate();
|
|
|
|
|
const { month: monthStr, data, onClick } = props;
|
|
|
|
|
const weekStartDayOffset = workspaceStore.state.generalSetting.weekStartDayOffset;
|
|
|
|
|
export const ActivityCalendar = memo(
|
|
|
|
|
observer((props: ActivityCalendarProps) => {
|
|
|
|
|
const t = useTranslate();
|
|
|
|
|
const { month: monthStr, data, onClick } = props;
|
|
|
|
|
const weekStartDayOffset = workspaceStore.state.generalSetting.weekStartDayOffset;
|
|
|
|
|
|
|
|
|
|
const { days, weekDays, maxCount } = useMemo(() => {
|
|
|
|
|
const yearValue = dayjs(monthStr).toDate().getFullYear();
|
|
|
|
|
const monthValue = dayjs(monthStr).toDate().getMonth();
|
|
|
|
|
const dayInMonth = new Date(yearValue, monthValue + 1, 0).getDate();
|
|
|
|
|
const firstDay = (((new Date(yearValue, monthValue, 1).getDay() - weekStartDayOffset) % 7) + 7) % 7;
|
|
|
|
|
const lastDay = new Date(yearValue, monthValue, dayInMonth).getDay() - weekStartDayOffset;
|
|
|
|
|
const prevMonthDays = new Date(yearValue, monthValue, 0).getDate();
|
|
|
|
|
|
|
|
|
|
const WEEK_DAYS = [t("days.sun"), t("days.mon"), t("days.tue"), t("days.wed"), t("days.thu"), t("days.fri"), t("days.sat")];
|
|
|
|
|
const weekDaysOrdered = WEEK_DAYS.slice(weekStartDayOffset).concat(WEEK_DAYS.slice(0, weekStartDayOffset));
|
|
|
|
|
|
|
|
|
|
const daysArray: CalendarDay[] = [];
|
|
|
|
|
|
|
|
|
|
// Previous month's days
|
|
|
|
|
for (let i = firstDay - 1; i >= 0; i--) {
|
|
|
|
|
daysArray.push({ day: prevMonthDays - i, isCurrentMonth: false });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Current month's days
|
|
|
|
|
for (let i = 1; i <= dayInMonth; i++) {
|
|
|
|
|
const date = dayjs(`${yearValue}-${monthValue + 1}-${i}`).format("YYYY-MM-DD");
|
|
|
|
|
daysArray.push({ day: i, isCurrentMonth: true, date });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Next month's days
|
|
|
|
|
for (let i = 1; i < 7 - lastDay; i++) {
|
|
|
|
|
daysArray.push({ day: i, isCurrentMonth: false });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const maxCountValue = Math.max(...Object.values(data), 1);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
year: yearValue,
|
|
|
|
|
month: monthValue,
|
|
|
|
|
days: daysArray,
|
|
|
|
|
weekDays: weekDaysOrdered,
|
|
|
|
|
maxCount: maxCountValue,
|
|
|
|
|
};
|
|
|
|
|
}, [monthStr, data, weekStartDayOffset, t]);
|
|
|
|
|
|
|
|
|
|
const today = useMemo(() => dayjs().format("YYYY-MM-DD"), []);
|
|
|
|
|
const selectedDateFormatted = useMemo(() => dayjs(props.selectedDate).format("YYYY-MM-DD"), [props.selectedDate]);
|
|
|
|
|
|
|
|
|
|
const { days, weekDays, maxCount } = useMemo(() => {
|
|
|
|
|
const yearValue = dayjs(monthStr).toDate().getFullYear();
|
|
|
|
|
const monthValue = dayjs(monthStr).toDate().getMonth();
|
|
|
|
|
const dayInMonth = new Date(yearValue, monthValue + 1, 0).getDate();
|
|
|
|
|
const firstDay = (((new Date(yearValue, monthValue, 1).getDay() - weekStartDayOffset) % 7) + 7) % 7;
|
|
|
|
|
const lastDay = new Date(yearValue, monthValue, dayInMonth).getDay() - weekStartDayOffset;
|
|
|
|
|
const prevMonthDays = new Date(yearValue, monthValue, 0).getDate();
|
|
|
|
|
|
|
|
|
|
const WEEK_DAYS = [t("days.sun"), t("days.mon"), t("days.tue"), t("days.wed"), t("days.thu"), t("days.fri"), t("days.sat")];
|
|
|
|
|
const weekDaysOrdered = WEEK_DAYS.slice(weekStartDayOffset).concat(WEEK_DAYS.slice(0, weekStartDayOffset));
|
|
|
|
|
|
|
|
|
|
const daysArray: CalendarDay[] = [];
|
|
|
|
|
|
|
|
|
|
// Previous month's days
|
|
|
|
|
for (let i = firstDay - 1; i >= 0; i--) {
|
|
|
|
|
daysArray.push({ day: prevMonthDays - i, isCurrentMonth: false });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Current month's days
|
|
|
|
|
for (let i = 1; i <= dayInMonth; i++) {
|
|
|
|
|
const date = dayjs(`${yearValue}-${monthValue + 1}-${i}`).format("YYYY-MM-DD");
|
|
|
|
|
daysArray.push({ day: i, isCurrentMonth: true, date });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Next month's days
|
|
|
|
|
for (let i = 1; i < 7 - lastDay; i++) {
|
|
|
|
|
daysArray.push({ day: i, isCurrentMonth: false });
|
|
|
|
|
}
|
|
|
|
|
return (
|
|
|
|
|
<div className={cn("w-full h-auto shrink-0 grid grid-cols-7 grid-flow-row gap-1")}>
|
|
|
|
|
{weekDays.map((day, index) => (
|
|
|
|
|
<div key={index} className={cn("w-6 h-5 text-xs flex justify-center items-center cursor-default opacity-60")}>
|
|
|
|
|
{day}
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
{days.map((dayInfo, index) => {
|
|
|
|
|
if (!dayInfo.isCurrentMonth) {
|
|
|
|
|
return (
|
|
|
|
|
<CalendarCell
|
|
|
|
|
key={`prev-next-${index}`}
|
|
|
|
|
dayInfo={dayInfo}
|
|
|
|
|
count={0}
|
|
|
|
|
maxCount={maxCount}
|
|
|
|
|
isToday={false}
|
|
|
|
|
isSelected={false}
|
|
|
|
|
tooltipText=""
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const date = dayInfo.date!;
|
|
|
|
|
const count = data[date] || 0;
|
|
|
|
|
const isToday = today === date;
|
|
|
|
|
const isSelected = selectedDateFormatted === date;
|
|
|
|
|
const tooltipText =
|
|
|
|
|
count === 0
|
|
|
|
|
? date
|
|
|
|
|
: t("memo.count-memos-in-date", {
|
|
|
|
|
count: count,
|
|
|
|
|
memos: count === 1 ? t("common.memo") : t("common.memos"),
|
|
|
|
|
date: date,
|
|
|
|
|
}).toLowerCase();
|
|
|
|
|
|
|
|
|
|
const maxCountValue = Math.max(...Object.values(data), 1);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
year: yearValue,
|
|
|
|
|
month: monthValue,
|
|
|
|
|
days: daysArray,
|
|
|
|
|
weekDays: weekDaysOrdered,
|
|
|
|
|
maxCount: maxCountValue,
|
|
|
|
|
};
|
|
|
|
|
}, [monthStr, data, weekStartDayOffset, t]);
|
|
|
|
|
|
|
|
|
|
const today = useMemo(() => dayjs().format("YYYY-MM-DD"), []);
|
|
|
|
|
const selectedDateFormatted = useMemo(() => dayjs(props.selectedDate).format("YYYY-MM-DD"), [props.selectedDate]);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className={cn("w-full h-auto shrink-0 grid grid-cols-7 grid-flow-row gap-1")}>
|
|
|
|
|
{weekDays.map((day, index) => (
|
|
|
|
|
<div key={index} className={cn("w-6 h-5 text-xs flex justify-center items-center cursor-default opacity-60")}>
|
|
|
|
|
{day}
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
{days.map((dayInfo, index) => {
|
|
|
|
|
if (!dayInfo.isCurrentMonth) {
|
|
|
|
|
return (
|
|
|
|
|
<CalendarCell
|
|
|
|
|
key={`prev-next-${index}`}
|
|
|
|
|
key={date}
|
|
|
|
|
dayInfo={dayInfo}
|
|
|
|
|
count={0}
|
|
|
|
|
count={count}
|
|
|
|
|
maxCount={maxCount}
|
|
|
|
|
isToday={false}
|
|
|
|
|
isSelected={false}
|
|
|
|
|
tooltipText=""
|
|
|
|
|
isToday={isToday}
|
|
|
|
|
isSelected={isSelected}
|
|
|
|
|
onClick={() => onClick?.(date)}
|
|
|
|
|
tooltipText={tooltipText}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const date = dayInfo.date!;
|
|
|
|
|
const count = data[date] || 0;
|
|
|
|
|
const isToday = today === date;
|
|
|
|
|
const isSelected = selectedDateFormatted === date;
|
|
|
|
|
const tooltipText =
|
|
|
|
|
count === 0
|
|
|
|
|
? date
|
|
|
|
|
: t("memo.count-memos-in-date", {
|
|
|
|
|
count: count,
|
|
|
|
|
memos: count === 1 ? t("common.memo") : t("common.memos"),
|
|
|
|
|
date: date,
|
|
|
|
|
}).toLowerCase();
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<CalendarCell
|
|
|
|
|
key={date}
|
|
|
|
|
dayInfo={dayInfo}
|
|
|
|
|
count={count}
|
|
|
|
|
maxCount={maxCount}
|
|
|
|
|
isToday={isToday}
|
|
|
|
|
isSelected={isSelected}
|
|
|
|
|
onClick={() => onClick?.(date)}
|
|
|
|
|
tooltipText={tooltipText}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
ActivityCalendar.displayName = "ActivityCalendar";
|
|
|
|
|
|