'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(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; };