Files
techtracker/apps/next/src/components/providers/lunch-reminder.tsx

69 lines
2.0 KiB
TypeScript

'use client';
import { useEffect, useRef } from 'react';
import { toast } from 'sonner';
import { useMutation, useQuery } from 'convex/react';
import { api } from '~/convex/_generated/api';
const nextOccurrenceMs = (hhmm: string, from = new Date()): number => {
const [hStr, mStr] = hhmm.split(':');
const target = new Date(from);
target.setHours(Number(hStr), Number(mStr), 0, 0);
if (target <= from) target.setDate(target.getDate() + 1);
return target.getTime() - from.getTime();
};
export const LunchReminder = () => {
const setStatus = useMutation(api.statuses.create);
const timeoutRef = useRef<number | null>(null);
const user = useQuery(api.auth.getUser);
const lunchTime = user?.lunchTime ?? '';
useEffect(() => {
const schedule = () => {
if (!lunchTime) return;
const ms = nextOccurrenceMs(lunchTime);
console.log('Ms = ', ms)
if (timeoutRef.current) clearTimeout(timeoutRef.current);
timeoutRef.current = window.setTimeout(() => {
void (async () => {
try {
if (
'Notification' in window &&
Notification.permission === 'granted'
) {
new Notification('Lunch time?', {
body: 'Update your status to "At lunch"?',
tag: 'tech-tracker-lunch',
});
}
} catch {}
toast('Lunch time?', {
description:
'Would you like to set your status to "At lunch"?',
action: {
label: 'Set to lunch',
onClick: () => void setStatus({ message: 'At lunch' }),
},
cancel: {
label: 'Not now',
onClick: () => console.log('User declined lunch suggestion'),
},
id: 'lunch-reminder',
});
schedule();
})();
}, ms);
};
schedule();
return () => {
if (timeoutRef.current) clearTimeout(timeoutRef.current);
};
}, [lunchTime, setStatus]);
return null;
};