repeating tasks UI improvements
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
export type Recurrence = {
|
||||
type: 'daily' | 'weekly' | 'monthly';
|
||||
days?: number[];
|
||||
dayOfMonth?: number;
|
||||
};
|
||||
|
||||
const startOfDay = (date: Date) => new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
||||
|
||||
const addDays = (date: Date, days: number) => {
|
||||
const d = new Date(date);
|
||||
d.setDate(d.getDate() + days);
|
||||
return d;
|
||||
};
|
||||
|
||||
const getNextDaily = (completedAt: Date) => addDays(startOfDay(completedAt), 1);
|
||||
|
||||
const getNextWeekly = (completedAt: Date, days: number[]) => {
|
||||
if (!days || days.length === 0) return null;
|
||||
const base = startOfDay(completedAt);
|
||||
for (let offset = 1; offset <= 7; offset++) {
|
||||
const candidate = addDays(base, offset);
|
||||
if (days.includes(candidate.getDay())) return candidate;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const getNextMonthly = (completedAt: Date, dayOfMonth?: number) => {
|
||||
if (!dayOfMonth || dayOfMonth < 1 || dayOfMonth > 31) return null;
|
||||
const base = startOfDay(completedAt);
|
||||
const baseDay = base.getDate();
|
||||
const startOffset = dayOfMonth > baseDay ? 0 : 1;
|
||||
|
||||
for (let offset = startOffset; offset <= 12; offset++) {
|
||||
const year = base.getFullYear();
|
||||
const monthIndex = base.getMonth() + offset;
|
||||
const candidate = new Date(year, monthIndex, dayOfMonth);
|
||||
if (candidate.getMonth() === (monthIndex % 12 + 12) % 12) {
|
||||
if (candidate.getTime() > completedAt.getTime()) {
|
||||
return startOfDay(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const getNextRecurrenceDate = (recurrence: Recurrence, completedAt: Date) => {
|
||||
if (recurrence.type === 'daily') return getNextDaily(completedAt);
|
||||
if (recurrence.type === 'weekly') return getNextWeekly(completedAt, recurrence.days || []);
|
||||
if (recurrence.type === 'monthly') return getNextMonthly(completedAt, recurrence.dayOfMonth);
|
||||
return null;
|
||||
};
|
||||
|
||||
export const getRecurrenceProgress = (
|
||||
recurrence: Recurrence | null | undefined,
|
||||
completedAtIso: string | null | undefined,
|
||||
nowMs: number
|
||||
) => {
|
||||
if (!recurrence || !completedAtIso) return null;
|
||||
const completedAt = new Date(completedAtIso);
|
||||
if (isNaN(completedAt.getTime())) return null;
|
||||
const next = getNextRecurrenceDate(recurrence, completedAt);
|
||||
if (!next) return null;
|
||||
const total = next.getTime() - completedAt.getTime();
|
||||
if (total <= 0) return null;
|
||||
const progress = (nowMs - completedAt.getTime()) / total;
|
||||
return Math.max(0, Math.min(1, progress));
|
||||
};
|
||||
Reference in New Issue
Block a user