69 lines
2.0 KiB
TypeScript
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;
|
|
};
|